项目中经常会有一些的功能模块用到runtime,最近也在学习它.对于要不要阅读runtime的源码,我觉得仅仅是处理正常的开发,那真的没有必要,只要把常用的一些函数看下和原理理解下就可以了.
但是如果真能静下心好好阅读源码,真的能帮你更加深入理解objc本身以及经过高阶包装出来的那些特性。
什么是runtime
runtime就是运行时,每个语言都有它的runtime.通俗点讲就是程序运行时发生的事情.
比如C语言,在编译的时候就决定了调用哪些函数,通过编译后就一步步执行下去,没有任何二义性,所以它是静态语言.
而objc的函数调用则可以理解为发消息,在编译的时候完全不能决定哪个函数执行,只有在运行的时候才会根据函数名找到函数调用,所以在运行的时候它能动态地添加调换属性,函数.所以它是动态语言.
动态和静态语言没有明显的界限,我感觉它们就是以runtime来区分的,看它在runtime时,有多灵活,那么它就有多动态.
相关定义
typedef struct objc_method *Method
struct objc_method {
SEL method_name;
char *method_types;
IMP method_imp;
}
SEL是char*,可以理解为函数的姓名.
IMP就是函数指针,指向函数的实现.
==在objc_class中method list保存了一个SEL<>IMP的映射.所以通过SEL可以找到函数的实现==
typedef struct objc_ivar *Ivar;
struct objc_ivar {
char *ivar_name;
char *ivar_type;
int ivar_offset;
#ifdef __LP64__
int space;
#endif
}
实例变量,跟某个对象关联,不能被静态方法使用,与之想对应的是类变量
typedef struct objc_category *Category;
struct objc_category {
char *category_name;
char *class_name;
struct objc_method_list *instance_methods;
struct objc_method_list *class_methods;
struct objc_protocol_list *protocols;
}
Catagory可以动态地为已经存在的类添加新的行为。比如类方法,实例方法,协议.
==根据结构可知,不能添加属性,实例变量==
struct objc_method_list {
struct objc_method_list *obsolete;
int method_count;
int space;
struct objc_method method_list[1];
}
struct objc_ivar_list {
int ivar_count;
int space;
struct objc_ivar ivar_list[1];
}
==简单地理解为存有方法和实例变量的数组==
//类在runtime中的表示
struct objc_class {
Class isa;//指针,顾名思义,表示是一个什么,
//实例的isa指向类对象,类对象的isa指向元类
#if !__OBJC2__
Class super_class; //指向父类
const char *name; //类名
long version;
long info;
long instance_size
struct objc_ivar_list *ivars //成员变量列表
struct objc_method_list **methodLists; //方法列表
struct objc_cache *cache;//缓存
//一种优化,调用过的方法存入缓存列表,下次调用先找缓存
struct objc_protocol_list *protocols //协议列表
#endif
};
struct objc_cache {
unsigned int mask;
unsigned int occupied;
Method buckets[1];
};
==objc_cache可以理解为存最近调用过的方法的数组,每次调用先访问它,提高效率==
runtime常用方法
@interface LYUser : NSObject
@property (nonatomic,strong)NSString *userId;
@property (nonatomic,strong)NSString *userName;
@property (nonatomic,strong)NSString *age;
@end
- (void)viewDidLoad {
[super viewDidLoad];
//利用runtime遍历一个类的全部成员变量
NSDictionary *userDict = @{@"userId":@"1",@"userName":@"levi",@"age":@"20"};
unsigned int count;
LYUser *newUser = [LYUser new];
objc_property_t *propertyList = class_copyPropertyList([LYUser class], &count);
for (int i = 0; i < count; i++) {
const char *propertyName = property_getName(propertyList[i]);
NSString *key = [NSString stringWithUTF8String:propertyName];
[newUser setValue:userDict[key] forKey:key];
}
NSLog(@"%@--%@--%@",newUser.userId,newUser.userName,newUser.age);
}
==这只是最简单的转化,还要考虑容错,转换效率,现在有很多开源框架做的很不错.这是一些开源框架的性能对比:==模型转换库评测结果
class_getInstanceMethod() //类方法和实例方法存在不同的地方,所以两个不同的方法获得
class_getClassMethod() //以上两个函数传入返回Method类型
method_exchangeImplementations //()交换两个方法的实现
==这个用到的地方很多,可以大大减少我们的代码量,常用的有防错措施,统计打点,统一