在category中声明@property,只会生成方法的生命。不会生成成员变量,也不会生成方法的现实现
如果在category里面时间写成员变量{
int _age;
}
会报错,说不能在category中声明成员变量。
但是可以间接添加。
怎么间接添加呢?
首先:Person(Test)的.h文件中还是要写上@property (nonatomic,assign)int age;
怪招1:
在
@implement Person(Test)
Int age_;
-(void)setAge:(int)age {
age_ = age;
}
-(int)age {
return age_
}
怪招1会导致所有的Person类的age值都是一样的。
怪招2:
@implement Person(Test)
+ (void)load {
ages_ = [NSMultableDictionary dictionary];
}
NSMultableDictionary *ages_;
-(void)setAge:(int)age {
NSString *key = [NSString stringWithFormat:@“%p”,self];
ages_[key] = @(age);
}
-(int)age {
NSString *key = [NSString stringWithFormat:@“%p”,self];
return [ages_[key].intValue];
}
怪招2,如果多个对象在不同线程同时访问,有可能有线程问题。
正规做法:关联对象。
#Import <objc/runtime>
objc_AssociationPolicy(绑定策略)的所有值的解析:
OBJC_ASSOCIATION_ASSIGN assign
OBJC_ASSOCIATION_RETAIN_NONATOMIC strong,nonatomic
OBJC_ASSOCIATION_COPY_NONATOMIC copy,nonatomic
OBJC_ASSOCIATION_RETAIN strong,atomic
OBJC_ASSOCIATION_COPY copy,atomic
使用:.h还是有一个@property (nonatomic, assign) age;
// 这样定义key是有漏洞的,别人可以通过extern const void *AgeKey;然后访问和修改(可以加上static const void*)。并且这样定义比较麻烦
const void *AgeKey = &AgeKey; // AgeKey这个const void对象,存的是自己的地址值,如0x39877834
@implement Person(Test)
// object:给谁绑定,key:绑定的key,value,绑定什么值,policy:绑定策略
// objc_setAssociatedObject(id _Nonnull object, const void *_Nonnull key, id _Nonnull value, objc_AssociatioinPolicy policy)
-(void)setAge:(int)age {
objc_setAssociatedObject(self, AgeKey, @(age), OBJC_ASSOCIATION_ASSIGN)
}
-(int)age {
return objc_getAssociatedObject(self, AgeKey).intValue;
}
======================================================================
static const char AgeKey;
-(void)setAge:(int)age {
objc_setAssociatedObject(self, &AgeKey, age, OBJC_ASSOCIATION_ASSIGN)
}
========================================================
如果在两个不同地方,写两个@“name”,其实是同一个来的,因为他们都放在常量区。
#define AGE_KEY @“age”
-(void)setAge:(int)age {
objc_setAssociatedObject(self, AGE_KEY, age, OBJC_ASSOCIATION_ASSIGN);
}
========================================================
@selector(age)不管写多少次,都是同一个,都是指向某个地址值
-(void)setAge:(int)age {
objc_setAssociatedObject(self, @selector(age), age, OBJC_ASSOCIATION_ASSIGN);
}
// _cmd相当于@selector(age) 当然,要保持跟setAge:方法中的一样,所以只能在age方法中写
-(int)age {
objc_getAssociatedObject(self, _cmd);
}
这种通过关联对象添加的属性,不会改变Person类这个结构体的结构,而且也不是存在Person类对象,也不是存储在Person实例对象里面的。
原理分析::
关联对象并不是存储在被关联对象本身的内存中
关联对象存储在全局的统一的AssociationsManager中
设置管理对象为nil,相当于是移除关联对象。 —》 比如person.age = nil; objc_setAssociatedObject(self, key, nil, policy)
移除关联对象:
Person *person = [Person alloc] init]
objc_removeAssociatedObjects(id object)
objc_removeAssociatedObjects(person);