1. [receiver message]
2. objc_msgSend(receiver, selector, arg1, arg2, ...)
3. id objc_msgSend ( id self, SEL op, ... );
4. typedef struct objc_object *id; typedef struct objc_selector *SEL;
5. struct objc_object {Class isa;};
6. typedef struct objc_class *Class;
从[receiver message]顺藤摸瓜 我们能够找到objc_class的结构体的指针,objc_class就是我们摸到的瓜,里面关联了它的超类,类名,成员变量,方法,缓存,还有附属协议。
在objc_class结构体中,ivars是objc_ivar_list指针;methodLists是指向objc_method_list指针的指针。可以动态修改*methodLists的值来添加成员方法,也就是Category的实现原理,解释了为什么不能添加属性的原因。任性的话可以在Category中添加@dynamic的属性,并利用运行期动态提供存取方法或干脆动态转发;或者干脆使用关联度对象(AssociatedObject)。
其中objc_ivar_list和objc_method_list 分别是成员变量列表和方法列表:
objc_ivar_list 存储了objc_ivar,每个objc_ivar都存储了个类的单个成员变量的信息。同理objc_method_list存储了objc_method,每个objc_method存储了类的方法的信息。
不知道你是否注意到了objc_class中也有一个isa对象,这是因为一个 ObjC 类本身同时也是一个对象,为了处理类和对象的关系,runtime 库创建了一种叫做元类 (Meta Class) 的东西,类对象所属类型就叫做元类,它用来表述类对象本身所具备的元数据。类方法就定义于此处,因为这些方法可以理解成类对象的实例方法。每个类仅有一个类对象,而每个类对象仅有一个与之相关的元类。当你发出一个类似[NSObject alloc]的消息时,你事实上是把这个消息发给了一个类对象 (Class Object) ,这个类对象必须是一个元类的实例,而这个元类同时也是一个根元类 (root meta class) 的实例。所有的元类最终都指向根元类为其超类。所有的元类的方法列表都有能够响应消息的类方法。所以当[NSObject alloc]这条消息发给类对象的时候,objc_msgSend()会去它的元类里面去查找能够响应消息的方法,如果找到了,然后对这个类对象执行方法调用。根元类的超类是NSObject,而isa指向了自己,而NSObject的超类为nil,也就是它没有超类。