ObjectC Class Method SEL IMP

本文参考地址: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/


你可能感兴趣的:(method,Class,imp,objectc,sel)