给分类添加成员变量
另一篇:关联对象 AssociatedObject 完全解析
.h
#import <Foundation/Foundation.h>
@interface NSObject (Person)
@property (nonatomic, copy) NSString *name;
@end
.m
#import "NSObject+Person.h"
#import <objc/runtime.h> /*或者 #import <objc/message.h>*/
static NSString *nameKey = @"nameKey"; //那么的key
@interface NSObject ()
@end
@implementation NSObject (Person)
/**
setter方法
*/
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, &nameKey, name, OBJC_ASSOCIATION_COPY);
}
/**
getter方法
*/
- (NSString *)name {
return objc_getAssociatedObject(self, &nameKey);
}
@end
在其他实例中调用
- (void)viewDidLoad {
NSObject *objc = [[NSObject alloc] init];
objc.name = @"almost";
NSLog(@"%@", objc.name);
}
关联策略是个枚举值,解释如下:
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
OBJC_ASSOCIATION_ASSIGN = 0, //关联对象的属性是弱引用
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, //关联对象的属性是强引用并且关联对象不使用原子性
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, //关联对象的属性是copy并且关联对象不使用原子性
OBJC_ASSOCIATION_RETAIN = 01401, //关联对象的属性是copy并且关联对象使用原子性
OBJC_ASSOCIATION_COPY = 01403 //关联对象的属性是copy并且关联对象使用原子性
};
关联对象本质
问: 可以用关联对象给分类添加成员变量, 那么关联对象保存在哪里?
- 关联对象由AssociationsManager管理在AssocitionsHashMap存储
- 所有关联对象的关联类容都在同一个全局容器中[所有分类的的关联对象都放在全局容器中]
源码:
id objc_getAssociatedObject(id object, const void *key) {
return _object_get_associative_reference(object, (void *)key);
}
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) {
_object_set_associative_reference(object, (void *)key, value, policy);
}
void objc_removeAssociatedObjects(id object)
{
if (object && object->hasAssociatedObjects()) {
_object_remove_assocations(object);
}
}
void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
// retain the new value (if any) outside the lock.
ObjcAssociation old_association(0, nil);
id new_value = value ? acquireValue(value, policy) : nil;
{
//关联对象管理, c++实现的一个类
AssociationsManager manager;
//是一个全局容器
AssociationsHashMap &associations(manager.associations());
disguised_ptr_t disguised_object = DISGUISE(object);
if (new_value) {
// break any existing association.
//根据对象指针查找对应的一个ObjectAssociationMap结构的map
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
// secondary table exists
ObjectAssociationMap *refs = i->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
old_association = j->second;
j->second = ObjcAssociation(policy, new_value);
} else {
(*refs)[key] = ObjcAssociation(policy, new_value);
}
} else {
// create the new association (first time).
ObjectAssociationMap *refs = new ObjectAssociationMap;
associations[disguised_object] = refs;
(*refs)[key] = ObjcAssociation(policy, new_value);
object->setHasAssociatedObjects();
}
} else {
//传value = nil,进入else 就可以擦除关联对象
// setting the association to nil breaks the association.
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
ObjectAssociationMap *refs = i->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
old_association = j->second;
refs->erase(j);
}
}
}
}
// release the old value (outside of the lock).
if (old_association.hasValue()) ReleaseValue()(old_association);
}
![]()
截屏2019-12-15下午8.21.52.png
- 根据图中由下往上
- 首先, 传入value("hello")和policy(OBJC_ASSOCIATION_COPY_NONATOMIC)封装成一个ObjcAssocation这样一个结构
- 再把ObjcAssocation和selector的key(text) 建立一个映射结构ObjcAssocationMap
- 最后把ObjcAssocationMap作为全局容器AssocationHashMap的一个value, 对应的key是DISGIUISE(obj)

截屏2019-12-15下午8.21.52.png











网友评论