ios进阶

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

2020-04-20  本文已影响0人  爱玩游戏的iOS菜鸟

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

属性 != 变量 分类中添加属性,但并不会添加成员变量及对应的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的常见用法

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

//.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);
}
上一篇下一篇

猜你喜欢

热点阅读