【iOS】——分类,扩展以及关联对象

打印 上一主题 下一主题

主题 550|帖子 550|积分 1650

1. 分类(Category)和扩展(Extension)

1) 分类(运行期)



  • 分类就是为已经存在的类,在运行时添加新的方法的一种机制。
  • 分类可以添加协议,类方法,实例方法和属性,不能添加实例变量。
  • 添加的属性就不会生成成员变量,也不会生成setter/getter方法,必要手动添加setter/getter方法。
2)扩展(编译期)



  • 扩展和分类很像,扩展只有声明部分,扩展中的定义的方法必要在类的实现部分去实现。
  • 可以定义协议,类方法,实例方法,属性和实例变量,在编译期将此中的定义的数据加到该类的数据类表中。假如不实现此中的方法,就会报错。
  • 由于系统的类的是实现部分不对用户开放,以是不能给系统的类添加扩展。
3)区别



  • 扩展在编译期决定,是类的一部分,和类的声明部分和实现部分共同组成类,陪同着类的产生而产生,消亡而消亡。扩展也可以用来潜伏类的私有部分。
  • 分类是在运行期决议的,扩展可以添加实例变量,分类不能添加实例变量,原因是在运行时,对象的内存结构就已经确定好了,假如添加实例变量,会粉碎类的内存结构。
2. 分类的实质

1)分类原理

  1. typedef struct category_t *Category;
  2. struct category_t {
  3.     const char *name; // 分类名
  4.     classref_t cls; // 类
  5.     struct method_list_t *instanceMethods;  // 实例方法
  6.     struct method_list_t *classMethods; // 类方法
  7.     struct protocol_list_t *protocols;  // 协议
  8.     struct property_list_t *instanceProperties; // 实例属性
  9.     // Fields below this point are not always present on disk.
  10.     struct property_list_t *_classProperties;   // 类属性
  11.     method_list_t *methodsForMeta(bool isMeta) {
  12.         if (isMeta) return classMethods;
  13.         else return instanceMethods;
  14.     }
  15.     property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
  16. };
复制代码
发现里面存在实例方法列表,类方法列表,实例属性列表与类属性列表。
2)分类的加载流程


  • 在编译阶段将分类中的方法、属性等编译到一个数据结构category_t。
  • 将分类中的方法、属性等归并到一个大数组中,反面参加编译的分类会在数组的前面。
  • 将归并后的分类数据(方法、属性、协议),插入到类原来数据的前面。
也就是说当分类中的方法与原始类中的方法重名时,会先去调用分类中实现的方法。
2. 关联对象

通过关联对象给分类添加属性
动态添加

  1. objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
复制代码


  • 参数一:id object : 给哪个对象添加属性,这里要给自己添加属性,用self。
  • 参数二:void * == id key : key值,根据key获取关联对象的属性的值,在objc_getAssociatedObject中通过次key得到属性的值并返回。
  • ** 参数三:**id value : 关联的值,也就是set方法传入的值给属性去生存。
  • 参数四:objc_AssociationPolicy policy : 策略,属性以什么形式生存。
取值

  1. objc_getAssociatedObject(id object, const void *key);
复制代码


  • 参数一:id object : 获取哪个对象里面的关联的属性。
  • 参数二:void * == id key : 什么属性,与objc_setAssociatedObject中的key相对应,即通过key值取出valu
移除关联对象

  1. - (void)removeAssociatedObjects
  2. {
  3.     // 移除关联对象
  4.     objc_removeAssociatedObjects(self);
  5. }
复制代码
应用

  1. //分类.h文件
  2. #import "LGPerson.h"
  3. NS_ASSUME_NONNULL_BEGIN
  4. @interface LGPerson (cat)
  5. @property (nonatomic, copy) NSString *lg_nickname;
  6. @property (nonatomic, copy) NSString *name;
  7. @end
  8. NS_ASSUME_NONNULL_END
  9. //分类.m文件
  10. #import "LGPerson+cat.h"
  11. #import <objc/runtime.h>
  12. @implementation LGPerson (cat)
  13. - (void)setName:(NSString *)name {
  14.     objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  15. }
  16. - (NSString *) name {
  17.     return objc_getAssociatedObject(self, _cmd);
  18. }
  19. @end
  20.   
  21. //main文件
  22. #import <Foundation/Foundation.h>
  23. #import "LGPerson+cat.h"
  24. int main(int argc, const char * argv[]) {
  25.     @autoreleasepool {
  26.         
  27.         LGPerson *t = [[LGPerson alloc] init];
  28.         t.name = @"1";
  29.         NSLog(@"%@", t.name);
  30.         
  31.     }
  32.     return 0;
  33. }
复制代码
运行结果:

总结:


  • 分类中没有成员列表,因此不能添加成员变量。但是有属性列表,可以添加属性的声明,但是不会合成set与get方法,假如要利用分类中的属性,必要利用关联对象。
  • 分类在运行的时间被整合到类中,扩展在编译的时间被整合到类中,因此分类中的方法不实现不会报错,扩展就会报错。
  • 扩展用于声明私有属性与方法。
  • 分类中的方法和类中的方法重名,分类中的方法会取代类中的方法。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

用多少眼泪才能让你相信

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表