@class SEL IMP

来源:互联网 发布:pyqt5 for windows 编辑:程序博客网 时间:2024/04/30 13:27


在objective c中,如果细心的话会发现,每个类中都会自动生成一个class 类型的isa,

[plain] view plaincopy
  1. @interface NSObject <NSObject> {  
  2.      Class    isa;  
  3.  }  
isa是什么,class又是什么呢,找到Class的定义我们会发现如下:

[plain] view plaincopy
  1. typedefstruct objc_class *Class;  

而objc_class以前的定义又如下,现在据说被封闭了,不知道有没有再作修改,总之方便我们理解就好:

[plain] view plaincopy
  1. struct objc_class {  
  2.      Class isa;  
  3.        
  4.      Class super_class;  
  5.        
  6.      const char *name;  
  7.        
  8.      long version;  
  9.      long info;  
  10.        
  11.      long instance_size;  
  12.      struct objc_ivar_list *ivars;  
  13.      struct objc_method_list **methodLists;   
  14.        
  15.      struct objc_cache *cache;  
  16.      struct objc_protocol_list *protocols;     
  17.  }  
于是我们就有了点头绪了,isa,is a pointer,是个指针(根据网上的资料,这样理解是最贴近事实的,不管你们信不信,反正我是信了),每个类都有一个class类型的指针isa,继承自NSObject中,继承关系,方法变量等信息都存放在isa中,isa作为一个隐藏的属性,会自动生成于每个类之中。有了这个前提,也就可以解释为什么我们可以根据@class来代替任意一个类了,看代码:

Human.h

[plain] view plaincopy
  1. #import <Foundation/Foundation.h>  
  2.   
  3. @interface Human : NSObject  
  4. -(void)say;  
  5. @end  

Human.m

[plain] view plaincopy
  1. #import "Human.h"  
  2.   
  3. @implementation Human  
  4. -(void)say  
  5. {  
  6.     NSLog(@"Human中的say方法");  
  7. }  
  8. @end  

main.h

[plain] view plaincopy
  1. #import <Foundation/Foundation.h>  
  2. #import "Human.h"  
  3. int main(int argc, const char * argv[])  
  4. {  
  5.   
  6.     @autoreleasepool {  
  7.           
  8.         Class c =NSClassFromString(@"Human");  
  9.         [[c new] say];  
  10.         //以上CLASS类型的c,就相当于Human类。  
  11.     }  
  12.     return 0;  
  13. }  

class可以灵活的代替别的类,SEL与其类似,不同的是SEL代替的是方法,可以方便的代替其他方法,class中是因为有isa属性保存有类的信息,而SEL是因为即使是在不同的类中,方法名只要相同,这两个方法的ID就相同,SEL就是根据这个ID来找到该方法,再根据调用该方法的类的不同来找到唯一的地址。看代码再作解释:

[plain] view plaincopy
  1. #import <Foundation/Foundation.h>  
  2.   
  3.   
  4. #import <Foundation/Foundation.h>  
  5.   
  6. @interface Human : NSObject  
  7. -(void)say;  
  8. @end  
  9. @implementation Human  
  10. -(void)say  
  11. {  
  12.     NSLog(@"Human中的say方法");  
  13. }  
  14. @end  
  15. //上面定义了一个human类,里面有一个say方法  
  16. @interface man:NSObject  
  17. {}  
  18. -(void)say; @end  
  19.   
  20. @implementation man  
  21. -(void)say  
  22. {  
  23.     NSLog(@"man中的say方法");  
  24. }  
  25. @end  
  26.   
  27. //在上面定义了一个man类,同样有一个say方法  
  28. int main(int argc, const char * argv[])  
  29. {  
  30.   
  31.     @autoreleasepool {  
  32.           
  33.         Class a =NSClassFromString(@"Human");  
  34.         Class b =NSClassFromString(@"man");  
  35.         //根据方法名say找到该方法的id,将sel与其绑定;  
  36.         SEL sel = NSSelectorFromString(@"say");  
  37.         [[a new] performSelector:sel];  
  38.         [[b new] performSelector:sel];  
  39.           
  40.           
  41.           
  42.     }  
  43.     return 0;  
  44. }  

结果如下:

[plain] view plaincopy
  1. 2012-03-13 10:13:24.900 String[2725:403] Human中的say方法  
  2. 2012-03-13 10:13:24.901 String[2725:403] man中的say方法  


通过以上代码我们会发现,SEL通过方法名绑定后,可以被多个类实例调用,找了些网上的资料,解释都是说方法名一样的话,ID会一样,地址仍不同,才会实现这样的效果,我们不谈论是否准确,但我个人认为这是目前最合理的解释。这种用法的优势一方面是灵活性更高,类似于多态,另一方面是,这种用法sel找方法时匹配的是ID而不是字符串方法名,所以在效率上会高一些。还有一种更终极的方法,直接对应方法的地址,这种方法效率最高,请看代码:

[plain] view plaincopy
  1. #import <Foundation/Foundation.h>  
  2.   
  3.   
  4. #import <Foundation/Foundation.h>  
  5.   
  6. @interface Human : NSObject  
  7. -(void)say;  
  8. @end  
  9. @implementation Human  
  10. -(void)say  
  11. {  
  12.     NSLog(@"Human中的say方法");  
  13. }  
  14. @end  
  15. //上面定义了一个human类,里面有一个say方法  
  16. @interface man:NSObject  
  17. {}  
  18. -(void)say; @end  
  19.   
  20. @implementation man  
  21. -(void)say  
  22. {  
  23.     NSLog(@"man中的say方法");  
  24. }  
  25. @end  
  26.   
  27. //在上面定义了一个man类,同样有一个say方法  
  28. int main(int argc, const char * argv[])  
  29. {  
  30.   
  31.     @autoreleasepool {  
  32.           
  33.         Human *human =[Human new];  
  34.         man *ma=[man new];  
  35.         //根据方法名say找到该方法的id,将sel与其绑定;  
  36.         SEL sel =@selector(say);//也可以这样写:SEL sel=NSSelectorFromString(@"say");  
  37.         IMP imp1 = [human methodForSelector:sel];       
  38.         IMP imp2 = [ma methodForSelector:sel];       
  39.   
  40.         imp1(human,sel);  
  41.         imp2(ma,sel);  
  42.         //因为每个方法都有自己的地址,这种方式直接找到地址区分相同ID的方法,效率最高,但灵活性不如SEL方式。  
  43.           
  44.     }  
  45.     return 0;  
  46. }  

输出语句:

[plain] view plaincopy
  1. 2012-03-13 10:35:21.446 String[3763:403] Human中的say方法  
  2. 2012-03-13 10:35:21.450 String[3763:403] man中的say方法  


今天这些内容不太好理解,我用自己理解的方式给大家再解释一遍,class用于代替类,增加灵活性,因为我们不知道什么时候会用到什么类,方法也是如此,所以SEL可以代替方法,每个方法有方法名,ID,地址,相同的方法名,ID也一样,正常情况下我们根据方法名找到方法,用SEL方法可以根据ID找到方法,而用IMP方式可以直接找到地址,但是灵活性不如SEL方法,虽然效率最高。好了,今天到此为止。


原文地址:http://blog.csdn.net/holydancer/article/details/7347399


0 0
原创粉丝点击