本系列主要参考资料:
Objective-C Runtime Reference
Objective-C Runtime Programming Guide
涉及主要文件:objc/message.h,objc/objc-api.h,objc/objc.h,objc/runtime.h

特酷吧[tekuba.net]采用"署名-非商业用途-保持一致"的创作共用协议,使用本文内容请遵循该协议
Objective-C Runtime是Objective-C的基础内容,理解了Objective-C Runtime对于掌握Objective-C的很多技术原理非常有用。特酷吧特别整理了Objective-C Runtime的内容,共六篇,本文是第二篇:
Objective-C Runtime分析(一)-Runtime初步
Objective-C Runtime分析(二)-Class,Method,SEL,IMP
Objective-C Runtime分析(三)-objc_msgSend
Objective-C Runtime分析(四)--Dynamic Method Resolution
Objective-C Runtime分析(五)-Message Forwarding
Objective-C Runtime分析(六)-Type Encodings & Declared Properties

本文参考地址:https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtHowMessagingWorks.html
本文主要分析了与Objective-C Runtime密切相关的几个数据类型/概念:Class , Method,,SEL , IMP ,他们都在objc/objc.h中定义。先来看看他们的定义。

折叠C/C++ Code复制内容到剪贴板
  1. typedef struct objc_class *Class;  
  2. typedef struct objc_object {  
  3.     Class isa;  
  4. } *id;//可以看到,iOS中很重要的id实际上就是objc_object的指针.而NSObject的第一个对象就是Class类型的isa。因此id可以标示所有基于NSObject的对象。  
  5. typedef struct objc_selector     *SEL;  
  6. #if !OBJC_OLD_DISPATCH_PROTOTYPES  
  7. typedef void (*IMP)(void /* id, SEL, ... */ );  
  8. #else  
  9. typedef id (*IMP)(id, SEL, ...);  
  10. #endif  


一,Class
Class 被定义为一个指向objc_class的结构体指针,表示一个类的类结构。objc_class在objc/objc_class.h中定义如下:

折叠C/C++ Code复制内容到剪贴板
  1. struct objc_class {  
  2.     Class isa;  
  3.   
  4. #if !__OBJC2__  
  5.     Class super_class                                        OBJC2_UNAVAILABLE;/*父类*/  
  6.     const char *name                                         OBJC2_UNAVAILABLE;/*类名称*/  
  7.     long version                                             OBJC2_UNAVAILABLE;/*版本信息*/  
  8.     long info                                                OBJC2_UNAVAILABLE;/*类信息*/  
  9.     long instance_size                                       OBJC2_UNAVAILABLE;/*实例大小*/  
  10.     struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;/*实例参数链表*/  
  11.     struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;/*类方法链表*/  
  12.     struct objc_cache *cache                                 OBJC2_UNAVAILABLE;/*类方法缓存*/  
  13.     struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;/*协议链表*/  
  14. #endif  
  15. } OBJC2_UNAVAILABLE;  


可见,Class是指向类结构体的指针,该类结构体含有一个指向其父类类结构的指针,该类方法的链表,该类方法的缓存以及其他信息。
NSObject 的class方法就返回这样一个指向其类结构的指针。每一个基于NSObject的类实例对象都有一个指向该对象的类结构的指针,叫做isa。通过该指针,对象可以访问它对应的类以及相应的父类。

二,Method
Method是Runtime内部定义的方法,Class中定义有一个objc_method_list,链表都是objc_method类型的,定义如下:

折叠C/C++ Code复制内容到剪贴板
  1. typedef struct objc_method *Method;  
  2. struct objc_method {  
  3.     SEL method_name                                          OBJC2_UNAVAILABLE;/*标示方法名称*/  
  4.     char *method_types                                       OBJC2_UNAVAILABLE;/*方法的参数类型*/  
  5.     IMP method_imp                                           OBJC2_UNAVAILABLE;/*指向该方法的具体实现的函数指针*/  
  6. }  
  7.       
  8. struct objc_method_list {  
  9.     struct objc_method_list *obsolete                        OBJC2_UNAVAILABLE;  
  10.   
  11.     int method_count                                         OBJC2_UNAVAILABLE;  
  12. #ifdef __LP64__  
  13.     int space                                                OBJC2_UNAVAILABLE;  
  14. #endif  
  15.     /* variable length structure */  
  16.     struct objc_method method_list[1]                        OBJC2_UNAVAILABLE;  
  17. }  


三,SEL
定义如下:
typedef struct objc_selector     *SEL;
标示该方法的名字/签名
示例:
-(void)helloTekuba:(NSString *)url port:(int)port
{
    NSLog(@"%@,%d",url,port);
}

NSLog(@"SEL = %s",@selector(helloTekuba:port:));
打印结果:
SEL = helloTekuba:port:
不同的类可以拥有相同的selector,不同类的实例对象performSelector相同的selector时,会在各自的方法链表中根据 selector 去查找具体的方法实现IMP, 然后用这个方法实现去执行具体的实现代码。这是一个动态绑定的过程,在编译的时候,我们不知道最终会执行哪一些代码,只有在执行的时候,通过selector去查询,我们才能确定具体的执行代码。

四,IMP
typedef id (*IMP)(id, SEL, ...);
我们知道 id是一个指向 objc_object 结构体的指针(请看本文前面objc_object的定义),该结构体只有一个成员isa,所以任何继承自 NSObject 的类对象都可以用id 来指代,因为 NSObject 的第一个成员实例就是isa。
IMP 是一个函数指针,这个被指向的函数包含一个接收消息的对象id, 调用方法的选标 SEL,以及不定个数的方法参数,并返回一个id。也就是说IMP是消息最终调用的执行代码,是方法真正的实现代码 。我们可以像在C语言里面一样使用这个函数指针。
NSObject 类中的methodForSelector:方法就是这样一个获取指向方法实现IMP 的指针,methodForSelector:返回的指针和赋值的变量类型必须完全一致,包括方法参数类型和返回值类型。

五,其他
Ivar
Runtime中用来表示instance variable,实例变量,跟某个对象关联,不能被静态方法使用,与之想对应的是class variable,其声明如下:
typedef struct objc_ivar *Ivar;

Category
Runtime中用来表示Category,其声明为:
typedef struct objc_category *Category;
Catagory可以动态地为已经存在的类添加新的行为。这样可以保证类的原始设计规模较小,功能增加时再逐步扩展。使用Category对类进行扩展时,不需要访问其源代码,也不需要创建子类。关于更多Catagory的知识可以参考:http://www.tekuba.net/program/312/
转载请注明来自特酷吧,本文地址:www.tekuba.net/program/336/
推荐阅读:
XCode lipo命令使用的一点知识
UINavigationController弹出(pop)和压入(push)操作的一个问题
IOS后台运行浅析
IOS7 Background Fetch后台应用程序刷新
IOS NSProcessInfo获取系统开机累计时间

想及时获取特酷吧的更新?想了解iOS,android开发最新技术动态,点击或扫描下方二维码下载“多识阅读”App,丰富的iOS,Android,Web等领域开发者博客随你订阅。

多识阅读