runtime:運行時機制
1. 是什麼?
- 1.1 runtime是一套比較底層的純C語言的API,runtime就是一個庫,一個C語言庫,包含了許多底層的C語言API
- 1.2平時我們編寫的OC代碼,在程序運行過程中,其實最終都是轉成了runtime的C語言代碼,runtime算是OC的幕後工作者,是整個OC的底層
- 1.3舉個例子
oc中的代碼:[Student alloc] init]經過runtime後,其實最終在底層生成C語言代碼:
objc_msgSend(objc_msgSend("Student","alloc"), "init")
objc_msgSend其實就是想某個對象發送什麼消息,這個函數第一個參數是類型或對象名,第二個參數是消息的名字,這些代碼比較底層
2. 用過嗎?怎麼用?
- 2.1 runtime是屬於OC的底層,可以進行一些非常底層的操作(用OC無法實現的,或者說不好實現)eg
- *在程序運行過程中,動態創建一個類,(比如KVO和KVC的底層實現)
- *在程序運行過程中,動態爲某個類添加屬性/方法,修改屬性值,修改方法
- *遍歷一個類中所有的屬性和實例變量和所有方法
3.
- 3.1相關的頭文件
- #import //消息發送機制,可以直接用底層函數,進行消息發送
- 3.2相關應用
- *NSCoding(歸檔和解擋)
- *字典轉模型(利用runtime遍歷模型對象的所有屬性,根據屬性名從字典中取出對應的值,設置到模型的屬性上)
- *kvo(利用runtime動態產生一個類)
- 3.3相關函數
msg_send:給對象發送消息,來自
class_copyMethodList,遍歷某個類中所有的方法,來自
class_copyIvarList,遍歷某個類中所有的實例變量的方法,來自
運行時必備常識:
1.Ivar:成員變量的意思
2.Method:成員方法的意思
3.property:屬性
- 你使用過Objective-C的運行時編程(Runtime Programming)麼?如果使用過,你用它做了什麼?你還能記得你所使用的相關的頭文件或者某些方法的名稱嗎?
runtime 運行時的動態添加屬性方法,
動態添加 set 方法
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
動態添加 get 方法
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);
具體方法使用如下
#import <UIKit/UIKit.h>
@interface UIControl (ReName)
@property (nonatomic, copy) NSString *reName;
@end
UIControl+ReName.m
#import "UIControl+ReName.h"
#import <objc/runtime.h>
static const char * RENAME_CONST = "RECONST";
@implementation UIControl (ReName)
-(void)setReName:(NSString *)reName
{
objc_setAssociatedObject(self, RENAME_CONST, reName, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
-(NSString *)reName
{
return objc_getAssociatedObject(self, RENAME_CONST);
}
@end
使用方法如下
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.reName = @"my name is new button";
NSLog(@"%@",button.reName);
}
常用的方法使用名稱
// 1.獲得類中的所有成員變量
Ivar*ivarList =class_copyIvarList([selfclass], &count);
//2.獲得方法的名字的字符串
NSSelectorFromString(_cmd)
//3.發送消息函數
objc_msgSend()
runtim 運行時 動態歸檔方法代碼如下
調用方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
Student *student = [[Student alloc] init];
student.name1 = @"sunlin";
student.age = 18;
student.name2 = @"sunlin";
student.name3 = @"sunlin";
student.name4 = @"sunlin";
student.name5 = @"sunlin";
student.name6 = @"sunlin";
student.name7 = @"sunlin";
// 歸檔文件的路徑
NSString *filePath = [NSHomeDirectory()stringByAppendingPathComponent:@"person.archiver"];
// 判斷該文件是否存在
if (![[NSFileManager defaultManager]fileExistsAtPath:filePath]) {
// 不存在的時候,歸檔存儲一個Student的對象
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
[archiver encodeObject:student forKey:@"student"];
[archiver finishEncoding];
BOOL success = [data writeToFile:filePath atomically:YES];
if (success) {
NSLog(@"歸檔成功!");
}
} else{
// 存在的時候,不再進行歸檔,而是解擋!
NSData *data = [NSData dataWithContentsOfFile:filePath];
NSKeyedUnarchiver *unArchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
Student *studentFromSaving = [unArchiver decodeObjectForKey:@"student"];
NSLog(@"%@, %lu", studentFromSaving.name7, studentFromSaving.age);
}
return YES;
}
Student.h
#import <Foundation/Foundation.h>
@interface Student : NSObject<NSCoding>
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, copy) NSString *name1;
@property (nonatomic, copy) NSString *name2;
@property (nonatomic, copy) NSString *name3;
@property (nonatomic, copy) NSString *name4;
@property (nonatomic, copy) NSString *name5;
@property (nonatomic, copy) NSString *name6;
@property (nonatomic, copy) NSString *name7;
@end
Student.m
#import "Student.h"
#import <objc/runtime.h>
@implementation Student
-(void)encodeWithCoder:(NSCoder *)aCoder
{
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([self class], &count);
for (int i = 0; i < count; i++) {
Ivar ivar = ivars[i];
const char *name =ivar_getName(ivar);
NSString *nameStr = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
id value = [self valueForKey:nameStr];
[aCoder encodeObject:value forKey:nameStr];
}
free(ivars);
}
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
if (self = [super init]) {
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([self class], &count);
for (int i = 0; i < count; i++) {
Ivar ivar = ivars[i];
const char *name = ivar_getName(ivar);
NSString *key = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
id value = [aDecoder decodeObjectForKey:key];
[self setValue:value forKey:key];
}
free(ivars);
}
return self;
}
@end