在伯乐在线看了7篇关于Objective-C Runtime的博文,确定很详尽也很深入。但是看起来有点凌乱,不容易懂。我认为Objective-C Runtime主要包括如下几个方便。
1、数据类型,怎样定义id,对象,class,成员,属性,方法,分类,协议等
2、消息执行逻辑,方法查找,方法缓存,动态添加。
3、对象关联。
在http://www.jianshu.com/p/b1a6c51cfe3e里面的7篇文章说得非常全面了,我就换个角度去总结吧。OC class的定义如下图
1、数据类型:
OC 1.0的就不说了,那都是历史了。上面可以看到class定义里面还是有isa的Class。这个到底是什么呢?带着问题,再看看object的定义。
struct objc_object { Class isa; };
object里面也包含了Class,这个Class又是什么呢?一个对象包含一个Class,我觉得很正常,也是可以直接理解为就是创造这个类对象的类呗,但是为什么class里面还包含了一个Class呢?这个到底是什么呢?这个类难道又是另外一个类创建的呢?细心的同学,的确会这些疑问。事实上OC里面还有一个隐藏的概念(Meta-class),class里面对应的isa就是该类的Meta-class。我觉得这个是OC很神奇的地方,不过也合理。对象方法和类方法分来加载和存放,的确可以节约内存和提高加载的效率。
怎么证明我说的是对的,不是瞎扯的呢?没错就是就是想办法打印类的地址。
NSLog(@"NSObject's class is %p", [NSObject class]);
NSLog(@"NSObject's class is %p",objc_getClass(class_getName([NSObject class])));
NSLog(@"NSObject's meta class is %p",objc_getMetaClass(class_getName([NSObject class])));
想学习的人,还是自己跑一跑代码吧,加深印象,通过打印的确发现两个地址是不同的。
2016-04-05 10:24:06.538 test[806:67538] NSObject's class is 0x765000
2016-04-05 10:24:06.538 test[806:67538] NSObject's class is 0x765000
2016-04-05 10:24:06.538 test[806:67538] NSObject's meta class is 0x765014
这样就证明的确有两个类。那么怎样知道Meta-class里面是存放类方法呢?没错,就是打印方法表。这个留给爱好者去干吧。最后再上一张经典的图,看不懂的就留言吧。
说完了最基本的类,可以说说其他的了,
id的定义
typedef struct objc_object *id;
成员列表
方法列表
方法的定义
typedef struct objc_method *Method;
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;
char *method_types OBJC2_UNAVAILABLE;
IMP method_imp OBJC2_UNAVAILABLE;
}
成员的定义
typedef struct objc_ivar *Ivar;
struct objc_ivar {
char *ivar_name OBJC2_UNAVAILABLE;
char *ivar_type OBJC2_UNAVAILABLE;
int ivar_offset OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
}
IMP的定义
typedef id (*IMP)(id, SEL, ...);
cache的定义
typedef struct objc_cache *Cache
struct objc_cache {
unsigned int mask
/* total = mask + 1 */
OBJC2_UNAVAILABLE;
unsigned int occupied OBJC2_UNAVAILABLE;
Method buckets[1] OBJC2_UNAVAILABLE;
};
Category的定义
typedef struct objc_category *Category;
struct objc_category {
char *category_name OBJC2_UNAVAILABLE; // 分类名
char *class_name OBJC2_UNAVAILABLE; // 分类所属的类名
struct objc_method_list *instance_methods OBJC2_UNAVAILABLE; // 实例方法列表
struct objc_method_list *class_methods OBJC2_UNAVAILABLE; // 类方法列表
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 分类所实现的协议列表
}
Protocol的定义
typedef struct objc_object Protocol;
最后我们发现,协议就是一个对象,Category和class很像。我们可以动态创建协议,但是好像没有方法修改Category。
还值得注意的是如下的定义,很有用。
struct objc_super { id receiver; Class superClass; };
2、消息执行逻辑
说到消息,肯定要提到msg_send的,msg_send的原型如下:
objc_msgSend(receiver, selector, arg1, arg2, ...)
receiver是一个非常值得关心的东西,例如[self class]和[super class],那他们的receiver到底是谁呢,上面还特意提到了struct objc_super,事实上super的receiver依然是self。
objc_msgSend的执行过程如下,很简单明了。但是这只是正常情况的调用过程。
好吧,我决定再上一张网上找的图,这个图比较全面。
这张图就是比完整了,包括动态调用的流程。这个调用过程没有例子是很难说得清楚的,在这里就不再展开说了,有了这个图,看伯乐在线的博文,也比较容易懂了。有机会的话,我写几个例子玩一玩吧。
3、对象关联
类本身是不支持动态添加成员的,除非你动态创建类的时候添加进去,一旦类注册了就不能再添加了,协议也是如此,一旦发布了,就不能修改了。这样不科学呀,很多时候我们需要动态添加成员,那怎么办呀?于是后来有了对象关联,当然还是可以添加属性的,setValue等
void objc_setAssociatedObject ( id object,constvoid*key, id value, objc_AssociationPolicy policy );
id objc_getAssociatedObject ( id object,constvoid*key );
void objc_removeAssociatedObjects ( id object );
对象关联比较简单,也挺常用的。
好了,关于Objective-C Runtime的总结就到此为止吧。以后有时间再折腾一下下。。。