在objective c中,若是细心的话会发现,每一个类中都会自动生成一个class 类型的isa,函数
@interface NSObject <NSObject> { Class isa; }
isa是什么,class又是什么呢,找到Class的定义咱们会发现以下:spa
typedefstruct objc_class *Class;
而objc_class之前的定义又以下,如今听说被封闭了,不知道有没有再做修改,总之方便咱们理解就好:指针
struct objc_class { Class isa; Class super_class; const char *name; long version; long info; long instance_size; struct objc_ivar_list *ivars; struct objc_method_list **methodLists; struct objc_cache *cache; struct objc_protocol_list *protocols; }
因而咱们就有了点头绪了,isa,is a pointer,是个指针,每一个类都有一个class类型的指针isa,继承自NSObject中,继承关系,方法变量等信息都存放在isa中,isa做为一个隐藏的属性,会自动生成于每一个类之中。有了这个前提,也就能够解释为何咱们能够根据@class来代替任意一个类了,看代码:code
Human.horm
#import <Foundation/Foundation.h> @interface Human : NSObject -(void)say; @end
Human.m对象
#import "Human.h" @implementation Human -(void)say { NSLog(@"Human中的say方法"); } @end
main.h继承
#import <Foundation/Foundation.h> #import "Human.h" int main(int argc, const char * argv[]) { @autoreleasepool { Class c =NSClassFromString(@"Human"); [[c new] say]; //以上CLASS类型的c,就至关于Human类。 } return 0; }
class能够灵活的代替别的类,SEL与其相似,不一样的是SEL代替的是方法,能够方便的代替其余方法,class中是由于有isa属性保存有类的信息,而SEL是由于即便是在不一样的类中,方法名只要相同,这两个方法的ID就相同,SEL就是根据这个ID来找到该方法,再根据调用该方法的类的不一样来找到惟一的地址。字符串
typedef struct objc_object *id; typedef struct objc_selector *SEL; #if !OBJC_OLD_DISPATCH_PROTOTYPES typedef void (*IMP)(void /* id, SEL, ... */ ); #else typedef id (*IMP)(id, SEL, ...); #endif
从上面的头文件中咱们能够看到,IMP定义为 id (*IMP) (id, SEL, …)。这样说来, IMP是一个指向函数的指针,这个被指向的函数包括id(“self”指针),调用的SEL(方法名),再加上一些其余参数。 IMP 就是一个函数指针,这个被指向的函数包含一个接收消息的对象id(self 指针), 调用方法的选标 SEL (方法名),以及不定个数的方法参数,并返回一个id。也就是说 IMP 是消息最终调用的执行代码,是方法真正的实现代码 。io
#if !OBJC_OLD_DISPATCH_PROTOTYPES OBJC_EXPORT void objc_msgSend(void /* id self, SEL op, ... */ ) __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0); OBJC_EXPORT void objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ ) __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0); #else
Methodform
typedef struct objc_method *Method;
typedef struct objc_method *Method; struct objc_method { SEL method_name; char *method_types; IMP method_imp; };
这个定义看上去包括了咱们上面说过的其余类型。也就是说,Method(咱们常说的方法)表示一种类型,这种类型与selector和实现(implementation)相关。
看代码再做解释:
#import <Foundation/Foundation.h> @interface Human : NSObject -(void)say; @end @implementation Human -(void)say { NSLog(@"Human中的say方法"); } @end
//上面定义了一个human类,里面有一个say方法
#import <Foundation/Foundation.h> @interface man:NSObject {} -(void)say; @end @implementation man -(void)say { NSLog(@"man中的say方法"); } @end
//在上面定义了一个man类,一样有一个say方法
int main(int argc, const char * argv[]) { @autoreleasepool { Class a =NSClassFromString(@"Human"); Class b =NSClassFromString(@"man"); //根据方法名say找到该方法的id,将sel与其绑定; SEL sel = NSSelectorFromString(@"say"); [[a new] performSelector:sel]; [[b new] performSelector:sel]; } return 0; }
结果以下:
2012-03-13 10:13:24.900 String[2725:403] Human中的say方法 2012-03-13 10:13:24.901 String[2725:403] man中的say方法
经过以上代码咱们会发现,SEL经过方法名绑定后,能够被多个类实例调用,找了些网上的资料,解释都是说方法名同样的话,ID会同样,地址仍不一样,才会实现这样的效果,咱们不谈论是否准确,但我我的认为这是目前最合理的解释。这种用法的优点一方面是灵活性更高,相似于多态,另外一方面是,这种用法sel找方法时匹配的是ID而不是字符串方法名,因此在效率上会高一些。还有一种更终极的方法,直接对应方法的地址,这种方法效率最高,请看代码:
#import <Foundation/Foundation.h> @interface Human : NSObject -(void)say; @end @implementation Human -(void)say { NSLog(@"Human中的say方法"); } @end
//上面定义了一个human类,里面有一个say方法
#import <Foundation/Foundation.h> @interface man:NSObject {} -(void)say; @end @implementation man -(void)say { NSLog(@"man中的say方法"); } @end
//在上面定义了一个man类,一样有一个say方法
int main(int argc, const char * argv[]) { @autoreleasepool { Human *human =[Human new]; man *ma=[man new]; //根据方法名say找到该方法的id,将sel与其绑定; SEL sel =@selector(say);//也能够这样写:SEL sel=NSSelectorFromString(@"say"); IMP imp1 = [human methodForSelector:sel]; IMP imp2 = [ma methodForSelector:sel]; imp1(human,sel); imp2(ma,sel); //由于每一个方法都有本身的地址,这种方式直接找到地址区分相同ID的方法,效率最高,但灵活性不如SEL方式。 } return 0; }
输出语句:
2012-03-13 10:35:21.446 String[3763:403] Human中的say方法 2012-03-13 10:35:21.450 String[3763:403] man中的say方法
今天这些内容不太好理解,我用本身理解的方式给你们再解释一遍,class用于代替类,增长灵活性,由于咱们不知道何时会用到什么类,方法也是如此,因此SEL能够代替方法,每一个方法有方法名,ID,地址,相同的方法名,ID也同样,正常状况下咱们根据方法名找到方法,用SEL方法能够根据ID找到方法,而用IMP方式能够直接找到地址,可是灵活性不如SEL方法,虽然效率最高。