本系列主要参考资料:
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中定义。先来看看他们的定义。

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

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

    复制内容到剪贴板
  • struct objc_class {  
  •     Class isa;  
  •   
  • #if !__OBJC2__  
  •     Class super_class                                        OBJC2_UNAVAILABLE;/*父类*/  
  •     const char *name                                         OBJC2_UNAVAILABLE;/*类名称*/  
  •     long version                                             OBJC2_UNAVAILABLE;/*版本信息*/  
  •     long info                                                OBJC2_UNAVAILABLE;/*类信息*/  
  •     long instance_size                                       OBJC2_UNAVAILABLE;/*实例大小*/  
  •     struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;/*实例参数链表*/  
  •     struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;/*类方法链表*/  
  •     struct objc_cache *cache                                 OBJC2_UNAVAILABLE;/*类方法缓存*/  
  •     struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;/*协议链表*/  
  • #endif  
  • } OBJC2_UNAVAILABLE;  

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

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

    复制内容到剪贴板
  • typedef struct objc_method *Method;  
  • struct objc_method {  
  •     SEL method_name                                          OBJC2_UNAVAILABLE;/*标示方法名称*/  
  •     char *method_types                                       OBJC2_UNAVAILABLE;/*方法的参数类型*/  
  •     IMP method_imp                                           OBJC2_UNAVAILABLE;/*指向该方法的具体实现的函数指针*/  
  • }  
  •       
  • struct objc_method_list {  
  •     struct objc_method_list *obsolete                        OBJC2_UNAVAILABLE;  
  •   
  •     int method_count                                         OBJC2_UNAVAILABLE;  
  • #ifdef __LP64__  
  •     int space                                                OBJC2_UNAVAILABLE;  
  • #endif  
  •     /* variable length structure */  
  •     struct objc_method method_list[1]                        OBJC2_UNAVAILABLE;  
  • }  

  • 三,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等领域开发者博客随你订阅。