Associated Objects

作者 Mattt 翻译者 Croath Liu

#import <objc/runtime.h>

Objective-C开发者应该小心谨慎地遵循这个危险咒语的各种准则。一个很好的原因的就是:混乱的运行时代码会改变运行在其架构之上的所有代码。

从利的角度来讲, <objc/runtime.h> 中的函数具有其他方式做不到的、能为应用和框架提供强大功能的能力。而从弊的角度来讲,它可能会会毁掉代码的sanity meter,一切代码和逻辑都可能被异常糟糕的副作用影响(terrifying side-effects)。

因此,我们怀着巨大的恐惧来思考这个与“魔鬼的交易”(Faustian bargain),一起来看看这个最多地被NSHipster读者们要求讲讲的主题之一:对象关联(associated objects)。


对象关联(或称为关联引用)本来是Objective-C 2.0运行时的一个特性,起始于OS X Snow Leopard和iOS 4。相关参考可以查看 <objc/runtime.h> 中定义的以下三个允许你将任何键值在运行时关联到对象上的函数:

  • objc_setAssociatedObject
  • objc_getAssociatedObject
  • objc_removeAssociatedObjects

为什么我说这个很有用呢?因为这允许开发者对已经存在的类在扩展中添加自定义的属性,这几乎弥补了Objective-C最大的缺点

NSObject+AssociatedObject.h

@interface NSObject (AssociatedObject)
@property (nonatomic, strong) id associatedObject;
@end

NSObject+AssociatedObject.m

@implementation NSObject (AssociatedObject)
@dynamic associatedObject;

- (void)setAssociatedObject:(id)object {
     objc_setAssociatedObject(self, @selector(associatedObject), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (id)associatedObject {
    return objc_getAssociatedObject(self, @selector(associatedObject));
}

通常推荐的做法是添加的属性最好是 static char 类型的,当然更推荐是指针型的。通常来说该属性应该是常量、唯一的、在适用范围内用getter和setter访问到:

static char kAssociatedObjectKey;

objc_getAssociatedObject(self, &kAssociatedObjectKey);

然而可以用更简单的方式实现:用selector。

下一篇文章

Method swizzling 用来改变已存在的 selector 映射的方法实现。Method swizzling 通过在运行时修改类的消息分发列表中 selector 与实现的映射使得在运行时修改方法的调用成为可能。