美文网首页
iOS-Category添加成员变量

iOS-Category添加成员变量

作者: 翀鹰精灵 | 来源:发表于2020-12-27 20:47 被阅读0次

    默认情况下,分类不能添加成员变量,我们可以通过 xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc 分类名XXX.m 转为c++查看一下分类的底层的本质结构组成,如下所示:

    01.png

    在终端通过 xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc Person+Test.m 命令生成Person+Test.cpp文件,查看Person+Test.cpp文件

    02.png

    这个结构体的分类底层结构如下:

    struct _category_t {
        const char *name;
        struct _class_t *cls;
        const struct _method_list_t *instance_methods;
        const struct _method_list_t *class_methods;
        const struct _protocol_list_t *protocols;
        const struct _prop_list_t *properties;
    };
    

    分类里面存在的内容示意:

    ① name 一般指的是类名
    ② cls 类
    ③ _method_list_t  *instance_methods 方法列表-对象方法
    ④ struct _method_list_t *class_methods 方法列表-类方法
    ⑤ _protocol_list_t *protocols 协议
    ⑥ _prop_list_t *properties 属性
    

    所以,分类里面也可以遵守协议,可以声明属性,可以写对象方法,类方法等。

    此时,当我们在一个分类里面声明一个age属性的时候并不会报错,但是外部Person类调用这个属性赋值的时候,并不会真正赋值,这是因为分类里面并没有自动帮age属性实现- (void)setAge:(NSInteger)age- (NSInteger)age方法以及_age的成员变量,未解决这个问题,苹果给我们提供了关联属性的方案。

    • 添加管理对象
    
    /**
       1.id  _Nonnull object 关联的对象
       2.const void * _Nonnull key 传入指针
       3.id  _Nullable value 管理的值
       4.objc_AssociationPolicy policy 管理策略
         4.1 OBJC_ASSOCIATION_ASSIGN = 0,
         4.2 OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,
         4.3 OBJC_ASSOCIATION_COPY_NONATOMIC = 3,
         4.4 OBJC_ASSOCIATION_RETAIN = 01401,
         4.5 OBJC_ASSOCIATION_COPY = 01403
         */
    objc_setAssociatedObject(id  _Nonnull NSObject, const void * _Nonnull key, id  _Nullable value, objc_AssociationPolicy policy);
    
    
    objc_AssociationPolicy 对应的修饰符
    OBJC_ASSOCIATION_ASSIGN = 0, assgin
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, strong , nonatomic
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3, copy , nonatomic
    OBJC_ASSOCIATION_RETAIN = 01401, strong,atomic
    OBJC_ASSOCIATION_COPY = 01403 copy,atomic
    • 获取管理对象
        /**
         1.id  _Nonnull object  关联的对象
         2.const void * _Nonnull key 传入的key
         */
        objc_getAssociatedObject(<#id  _Nonnull object#>, <#const void * _Nonnull key#>);
    
    • 移除所有的关联对象
        /**
         1.id  _Nonnull object 管理对象
         */
        objc_removeAssociatedObjects(<#id  _Nonnull object#>)
    
    项目中使用示例如下:
    【用法1】
    static const void *NameKey = &NameKey;
    static const void *WeightKey = &WeightKey;
    - (void)setName:(NSString *)name {
        objc_setAssociatedObject(self, NameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    
    - (NSString *)name {
        return objc_getAssociatedObject(self, NameKey);
    }
    
    - (void)setWeight:(int)weight {
        objc_setAssociatedObject(self, WeightKey, @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    - (int)weight {
        return [objc_getAssociatedObject(self, WeightKey) intValue];
    }
    
    【用法2】
    static const char NameKey;
    static const char WeightKey;
    - (void)setName:(NSString *)name {
        objc_setAssociatedObject(self, &NameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    
    - (NSString *)name {
        return objc_getAssociatedObject(self, &NameKey);
    }
    
    - (void)setWeight:(int)weight {
        objc_setAssociatedObject(self, &WeightKey, @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    - (int)weight {
        return [objc_getAssociatedObject(self, &WeightKey) intValue];
    }
    
    【用法3】
    #define MJNameKey @"name"
    #define MJWeightKey @"weight"
    - (void)setName:(NSString *)name {
        objc_setAssociatedObject(self, MJNameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    
    - (NSString *)name {
        return objc_getAssociatedObject(self, MJNameKey);
    }
    
    - (void)setWeight:(int)weight {
        objc_setAssociatedObject(self, MJWeightKey, @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    - (int)weight {
        return [objc_getAssociatedObject(self, MJWeightKey) intValue];
    }
    
    【用法4】
    ///用法3
    - (void)setName:(NSString *)name {
        objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    
    - (NSString *)name {
        // 隐式参数
        // _cmd == @selector(name)
        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];
    }
    

    开发中本人多用前两种写法居多。后面两种仅供学习了解。方法1 vs 方法2 ,void *NameKey是个指针变量,需要占用8个字节, char NameKey只占一个字节,更节省内存空间。

    相关文章

      网友评论

          本文标题:iOS-Category添加成员变量

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