美文网首页ios进阶
Objective - C 关联对象(一) 如何添加"成员变量"

Objective - C 关联对象(一) 如何添加"成员变量"

作者: 爱玩游戏的iOS菜鸟 | 来源:发表于2020-04-20 14:49 被阅读0次

    (一)分类 - 能否添加“成员变量”

    • 因为分类底层结构的限制,不能直接添加成员变量到分类中
    • 但可以通过关联对象间接实现

    属性 != 变量 分类中添加属性,但并不会添加成员变量及对应的set、get方法

    (1)如何获得类似以前成员变量的效果

    方法一:定义全局变量 通过set、get方法存取

    NSInteger weight_;
    
    -(void)setWeight:(NSInteger)weight{
        weight_ = weight;
    }
    
    -(NSInteger)weight{
        return weight_;
    }
    

    缺点:多个对象共用一个全局变量

    方法二:使用NSDictionary存取不同对象的值

    NSMutableDictionary *weights_;
    
    +(void)load{
        weights_ = [NSMutableDictionary dictionary];
    }
    
    -(void)setWeight:(NSInteger)weight{
        NSString *key = [NSString stringWithFormat: @"%p",self];//使用self的内存地址作key 保证唯一
        weights_[key] = @(weight);
    }
    
    -(NSInteger)weight{
        NSString *key = [NSString stringWithFormat: @"%p",self];
        return [weights_[key] intValue];
    }
    

    缺点:1.虽然从外部无法看出区别,但是实际存储位置有区别 成员变量是存储在对象内部,而通过dictionary存储在全局字典对象 2.同时访问存在线程问题 不同的对象在不同的线程同时访问set方法时 3.添加多个变量时 需要定义多个去全局变量

    (2)方法三:关联对象

    这就是本章的重点,通过关联对象来添加“成员变量”

    关联对象提供了以下API:

    1. 添加关联对象 void objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy)
    2. 获得关联对象 id objc_getAssociatedObject(id object, const void * key)
    3. 移除所有的关联对象 void objc_removeAssociatedObjects(id object)
    #import <objc/runtime.h>
    
    #define ZQNameKey @"name"
    //使用宏 更安全的保证set、get的使用的key一致
    
    @implementation ZQPerson (Test)
    
    static const char ZQName;   //也可以使用static const NSString *ZQName = @"ZQNameKey";
    static const char ZQHeight; //但是我们用char 更节约内存 且我们并不需要变量内容 只需要变量地址而已
    
    -(void)setName:(NSString *)name{
        objc_setAssociatedObject(self, &ZQName, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
        //objc_setAssociatedObject(self, ZQNameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
        //方法二:也可以直接使用同一个字符串 因为字符串常量存储在常量区 地址也不会改变
        //objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
        //方法三:※推荐使用@selector(obj)  返回的是一个指向一个结构体的指针
        //优点:1.可读性更高 2.编译器提示
    }
    
    -(NSString *)name{
        return objc_getAssociatedObject(self, &ZQName);
        //return objc_getAssociatedObject(self, ZQNameKey);
        //return objc_getAssociatedObject(self, @selector(name));也能改成return objc_getAssociatedObject(self, _cmd);
        //隐式参数  _cmd = @selector(name) set和get不可同时使用
        // _cmd表示当前方法 因为key要一致 所以不能同时使用
    }
    
    -(void)setWeight:(NSInteger)weight{
        objc_setAssociatedObject(self, &ZQHeight, @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    -(NSInteger)weight{
        return [objc_getAssociatedObject(self, &ZQHeight) intValue];
    }
    
    

    (3)objc_AssociationPolicy 对应的修饰符

    image.png

    总结一下,key的常见用法

    • static void *MyKey = &MyKey;
      objc_setAssociatedObject(obj, MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
      objc_getAssociatedObject(obj, MyKey)

    • static char MyKey;
      objc_setAssociatedObject(obj, &MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
      objc_getAssociatedObject(obj, &MyKey)

    • 使用属性名作为key
      objc_setAssociatedObject(obj, @"property", value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
      objc_getAssociatedObject(obj, @"property");

    • 使用get方法的@selecor作为key(set也可以,get更直观)
      objc_setAssociatedObject(obj, @selector(getter), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
      objc_getAssociatedObject(obj, @selector(getter))

    通过上面多个方法对比,推荐使用方法:

    //.h
    @property(nonatomic,copy) NSString *name;
    @property(nonatomic,assign) NSInteger weight;
    
    @property(nonatomic,class,copy) NSString *sex;
    
    //.m
    
    //实例对象
    -(void)setName:(NSString *)name{
        objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    
    -(NSString *)name{
        return objc_getAssociatedObject(self, _cmd);
    }
    
    //类对象
    + (void)setSex:(NSString *)sex{
        objc_setAssociatedObject([self class], @selector(sex), sex, OBJC_ASSOCIATION_COPY_NONATOMIC);
    
    }
    
    + (NSString *)sex{
        return objc_getAssociatedObject([self class], _cmd);
    }
    

    相关文章

      网友评论

        本文标题:Objective - C 关联对象(一) 如何添加"成员变量"

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