关联对象

  • 默认情况下,因为分类底层结构的限制,不能添加==成员变量==到分类中,但可以通过==关联对象==来间接实现
  • 关联对象提供了以下API:
    • 添加关联对象
      • 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的常见用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static void *MyKey = &MyKey;
objc_setAssociatedObject(obj, MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, MyKey)

static 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,关联策略

1
2
3
4
5
6
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

关联对象的原理

  • 实现关联对象技术的核心对象有
    • AssociationsManager
    • AssociationsHashMap
    • ObjectAssociationMap
    • ObjcAssociation

objc4源码:objc-references.mm

AssociationsManager

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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

1
2
3
4
5
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

1
2
3
4
5
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); }
};

ObjcAssociation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class ObjcAssociation {

uintptr_t _policy;
id _value;

public:
ObjcAssociation(uintptr_t policy, id value) : _policy(policy), _value(value) {}
ObjcAssociation() : _policy(0), _value(nil) {}

uintptr_t policy() const { return _policy; }
id value() const { return _value; }

bool hasValue() { return _value != nil; }
};

notes:

  • 关联对象并不是存储在被关联对象本身内存中
  • 关联对象存储在全局的统一的一个AssociationsManager中
  • 设置关联对象为nil,就相当于是移除关联对象
  • 即为以下的关系:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    AssociationsManager
    AssociationsHashMap *_map;

    AssociationsHashMap
    disguised_ptr_t ObjectAssociationMap
    disguised_ptr_t ObjectAssociationMap
    ... ...

    AssociationsMap
    void * ObjectAssociation
    void * ObjectAssociation
    ... ...

    ObjectAssociation
    uintptr_t _policy;
    id _value;

参考