在我们一个类中如果不希望直接在.m文件添加方法,这样会造成代码量暴涨,我们可以使用分类category去增加方法,但是当我们需要在category中添加属性时候,我们要用到runtime关联去绑定一个属性到我们类对象,现在来看看runtime实现,这里借一张图,我主要介绍下其他文章没有提到的点,当我们在分类设置二个关联对象callback和name
- (void)setCallBack:(CallBack)callback{
objc_setAssociatedObject(self, @selector(callback), callback, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (CallBack)callback
{
return objc_getAssociatedObject(self, _cmd);
// return objc_getAssociatedObject(self, @selector(callback));
}
- (void)setName:(CallBack)name{
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (CallBack)name
{
return objc_getAssociatedObject(self, _cmd);
// return objc_getAssociatedObject(self, @selector(callback));
}
复制代码
我们可以看到这个方法具体实现
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
复制代码
这个函数内部实现,具体我们要先看看runtime内部几个数据结构,有一个单例AssociationsHashMap
spinlock_t AssociationsManagerLock;class AssociationsManager {
// associative references: object pointer -> PtrPtrHashMap.
static AssociationsHashMap *_map;
public:
AssociationsManager() { AssociationsManagerLock.lock(); }
~AssociationsManager() { AssociationsManagerLock.unlock(); }
AssociationsHashMap &associations() {
if (_map == NULL)
_map = new AssociationsHashMap();
return *_map;
}};
AssociationsHashMap *AssociationsManager::_map = NULL;复制代码
我们可以看看AssociationsHashMap这个c++类的具体结构
typedef ObjcAllocator<std::pair<void * const, ObjcAssociation> > ObjectAssociationMapAllocator; class ObjectAssociationMap : public std::map<void *, ObjcAssociation, ObjectPointerLess, ObjectAssociationMapAllocator> { public: void *operator new(size_t n) { return ::malloc(n); } void operator delete(void *ptr) { ::free(ptr); } }; typedef ObjcAllocator<std::pair<const disguised_ptr_t, ObjectAssociationMap*> > AssociationsHashMapAllocator; class AssociationsHashMap : public unordered_map<disguised_ptr_t, ObjectAssociationMap *, DisguisedPointerHash, DisguisedPointerEqual, AssociationsHashMapAllocator> { public: void *operator new(size_t n) { return ::malloc(n); } void operator delete(void *ptr) { ::free(ptr); } };复制代码
所以可以看到ObjectAssociationMap这个结构是继承map,map底层是红黑树的数据结构,而AssociationsHashMap则是继承unordered_map是一个哈希表,所以当我们在代码中调用obj对象category中的setter方法时也即- (void)setCallBack:(CallBack)callback和setName时
- (void)viewDidLoad {
[super viewDidLoad];
Obj *obj = [Obj alloc] init];
[obj setCallBack:cb];
[obj setName:cb];
Obj *obj2 = [Obj alloc] init];
[obj2 setCallBack:cb];
[obj2 setName:cb];}复制代码
我们可以看到,他其实会将两个参数传过去,obj对象地址和cb参数传入objc_setAssociatedObject函数中
objc_setAssociatedObject(obj, @selector(callback), cb, OBJC_ASSOCIATION_COPY_NONATOMIC);
objc_setAssociatedObject(obj2, @selector(name), cb, OBJC_ASSOCIATION_COPY_NONATOMIC);
复制代码
首先会根据obj这个对象地址在AssociationsHashMap哈希表中查找, 返回的是一个迭代器,如果在哈希表中查找到,就取出ObjectAssociationMap,这是map,他的节点包含键值对std::pair<void *, ObjcAssociation>,第一个参数key实际就是我们@selector(callback),第二个参数就是ObjcAssociation结构体,这个参数是我们传递进去value和policy
AssociationsHashMap &associations(manager.associations());
disguised_ptr_t disguised_object = DISGUISE(object); if (new_value) {
// break any existing association.
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();
}
}
复制代码
网上有张图已经画出他们的层次关系,三层之间的包含AssociationsHashMap(哈希表,时间复杂度为O(1)
) -> ObjectAssociationMap(map,底层红黑树,查找的时间复杂度O(logN)) -> ObjcAssociation(存储值value和策略policy),所以我们查找关联的时间复杂度O(logN)。
接着我自己画了一个关联数据模型
objc_setAssociatedObject(obj, @selector(callback), cb, OBJC_ASSOCIATION_COPY_NONATOMIC);
复制代码
先根据第一个参数对象地址obj在AssociationsHashMap哈希表中查找到ObjectAssociationMap,在根据ObjectAssociationMap中的@selector(callback)查找到ObjcAssociation,时间复杂度O(logN),然后替换或取出ObjcAssociation中的value值
我们在看看这两个类,ObjectAssociationMapAllocator和AssociationsHashMapAllocator两个内存分配器直接用的系统malloc和free函数,没有用stl内存池的实现方式
pointer allocate(size_type n, const_pointer = 0) {
return static_cast<pointer>(::malloc(n * sizeof(T)));
}
void deallocate(pointer p, size_type) { ::free(p); }复制代码