首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > 移动开发 >

objective C中的@class, SEL , IMP等灵便机制(五)

2013-10-16 
objective C中的@class, SEL , IMP等灵活机制(五)holydancer原创,如需转载,请在显要位置注明:转自holydanc

objective C中的@class, SEL , IMP等灵活机制(五)

holydancer原创,如需转载,请在显要位置注明:

转自holydancer的CSDN专栏,原文地址:http://blog.csdn.net/holydancer/article/details/7347399

?

在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方法,虽然效率最高。好了,今天到此为止。

?

关键字:objective-c ,objective c , oc ,@class, SEL ,selector ,IMP

热点排行