美文网首页
OC Category 的几个点

OC Category 的几个点

作者: Gxdy | 来源:发表于2018-09-04 11:29 被阅读0次

Category 的结构引申

附加:Category 的处理过程

  1. Xcode在编译时,会将所有参与编译的分类转变成一个c++结构体(图1所示)


    图片 1.png
  2. 运行时通过runtime加载所有category数据,并将其方法、属性、协议数据按照编译顺序,分别合并到一个对应的大数组
    [后编译的在数组的前面] ----> 这样方法调用时就会优先调用后编译的分类方法
  3. 将合并后的分类数据(方法、属性、协议),插入到类(类对象、元类对象)原来数据的前面 ----> 优先调用分类方法

综上概括:

  1. 本质上所有对象方法、协议、属性最终都会按照分类在前,原类在后;后编译的分类在前,先编译在后的原则,分别存放在类对象对象方法、协议、属性对应的数组里面
  2. 所有类方法最终都会按照分类在前,原类在后;后编译的分类在前,先编译在后的原则,存放在元类对象类方法数组里面

结论

  1. 最终方法或属性等都一个数组,且有序,所以就有了方法调用顺序:后编译的分类方法-->先编译的分类方法-->类对象(元类对象)原来的方法
  2. 因为程序运行时runtime是把所有分类数据合并到原类所有数据中,所以不管有没有import 某个分类的头文件,这个分类中 重写的方法都会可能被调用
  3. 分类结构体中包含有属性数组``struct property_list *instanceProperties;,所以分类允许添加属性的,但需要手动实现getter 和setter(@proterty... 在分类声明属性,只会生成属性的getter 和setter声明,但不会实现,和生成带_的成员变量
  4. 分类结构体中不含有成员变量数组``struct property_list *instanceProperties;,可见分类不存在成员变量,也不能添加成员变量



拓展:如何给分类添加成员变量

  1. 上述结论中谈到:由于分类结构限制,分类不存在成员变量,也不能添加成员变量,但是我们可以用伪成员变量实现类似效果的
  1. 实现方案:
    a. 在分类interface用中@property声明一个属性
    b. 在分类implementation中实现属性的 getter 和setter。由于分类不能添加和生成成员变量,所以最常用且可靠的方案是通过Runtime API关联一个伪成员变量,来实现getter 和setter方法
  1. 关联对象的相关Runtime API
// 添加关联对象
void objc_setAssociatedObject(id object, 
                              const void * key,
                              id value,
                              objc_AssociationPolicy policy)
//  获得关联对象
id objc_getAssociatedObject(id object, const void * key)
// 移除所有的关联对象
void objc_removeAssociatedObjects(id object)

/** 参数说明:
 *  object :id类型, 一般都传 self;用途相当于一个字典的Key,
            用来归类所关联的成员变量; 
 *  key :const void * 类型指针,相当于读写属性值的Key,
         可以传用@selector(getter) --》 [这样能免除繁琐的宏或常量定义]
 *  value : 成员变量的值 (对象)
 *  objc_AssociationPolicy policy : 内存策略,相当于retain、strong、copy等
  1. 示例
#import <objc/runtime.h>

@interface TLPerson (ExampleCode)

@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic) int weight;
@end

@implementation TLPerson (ExampleCode)

- (void)setName:(NSString *)name
{
    /* policy 参数类型
    typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,          
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,                                            
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,  
    OBJC_ASSOCIATION_RETAIN = 01401,      
    OBJC_ASSOCIATION_COPY = 01403      
    };*/
    objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)name
{
    // 隐式参数
    // _cmd == @selector(name),
    // 用@selector(name)作为key,可以简化代码,省去一些宏定义,还有能有代码提示
    return objc_getAssociatedObject(self, _cmd);
}

- (void)setWeight:(int)weight
{
    objc_setAssociatedObject(self, @selector(weight), @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (int)weight
{
    // _cmd == @selector(weight)
    return [objc_getAssociatedObject(self, _cmd) intValue];
}

@end

相关文章

网友评论

      本文标题:OC Category 的几个点

      本文链接:https://www.haomeiwen.com/subject/xwgwwftx.html