如何实现给分类“添加成员变量”?
默认情况下,因为分类底层结构的限制,不能添加成员变量到分类中。可以通过关联对象来间接实现
尝试过程
1、添加全局变量可以保存值,但是是全局性的会覆盖以前的值
@implementation TGPerson (Test)
intweight_;
- (void)setWeight:(int)weight {
weight_= weight;
}
- (int)weight {
return weight_;
}
@end
2、 添加全局字典,线程安全
@implementation TGPerson (Test)
NSMutableDictionary *weights_;
+ (void)load {
weights_ = [NSMutableDictionary dictionary];
}
- (void)setWeight:(int)weight {
NSString *key = [NSString stringWithFormat:@"%p", self];
weights_[key] =@(weight);
}
- (int)weight {
NSString *key = [NSString stringWithFormat:@"%p", self];
return [weights_[key] intValue];
}
@end
2、关联对象
- 设置关联对象
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)
key的常见用法
- static void *MyKey = &MyKey;(用自己的地址值)
objc_setAssociatedObject(obj,MyKey,value,OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj,MyKey)
- static const 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
objc_setAssociatedObject(obj,@selector(getter),value,OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj,@selector(getter))
objc_AssociationPolicy
image关联对象原理
关联对象核心对象
-
AssociationsManager
-
AssociationsHashMap
-
ObjectAssociationMap
-
ObjcAssociation (存放 value,policy,关联对象的值存在这个对象里)
源码解读
objc-references.mm
classAssociationsManager {
static AssociationsHashMap *_map;
public:
AssociationsManager() { AssociationsManagerLock.lock(); }
~AssociationsManager() { AssociationsManagerLock.unlock(); }
AssociationsHashMap&associations() {
if(_map==NULL)
_map = new AssociationsHashMap();
return*_map;
}
};
//objc_removeAssociatedObjects 移除关联对象
classObjcAssociation {
uintptr_t_policy;
id_value;
public:
ObjcAssociation(uintptr_tpolicy,idvalue) :_policy(policy),_value(value) {}
ObjcAssociation() :_policy(0),_value(nil) {}
uintptr_t policy() const { return _policy; }
idvalue()const{return_value; }
boolhasValue() {return_value!=nil; }
};
void_object_remove_assocations(idobject) {
vector< ObjcAssociation,ObjcAllocator<ObjcAssociation> > elements;
{
AssociationsManager manager;
AssociationsHashMap&associations(manager.associations());
if(associations.size() ==0)return;
disguised_ptr_tdisguised_object =DISGUISE(object);
AssociationsHashMap::iterator i = associations.find(disguised_object);
if(i != associations.end()) {
// copy all of the associations that need to be removed.
ObjectAssociationMap*refs = i->second;
for(ObjectAssociationMap::iterator j = refs->begin(), end = refs->end(); j != end; ++j) {
elements.push_back(j->second);
}
deleterefs;
associations.erase(i);
}
}
for_each(elements.begin(), elements.end(), ReleaseValue());
}
image
小结
-
关联对象并不是存储在被关联对象本身内存中
-
关联对象存储在全局的统一的一个AssociationsManager中
-
设置关联对象为nil,就相当于是移除关联对象
-
对关联的object没有引用,操作的是地址,object销毁 关联对象也会移除
网友评论