在ios 3.1和 os x 10.6系统里,苹果公司在objective-c运行时添加了一个associative references
特性。从本质上来说,这意味着每人上对象都有一个optional dictionary,你可以在这个dictionary
中添加键/值对。
这是一个很强大的特性,特别当考虑到objective-c原本有的一个categories特性。然而,
categories不允许你为类增加额外的实例变量。而使用associative references,为类添加伪
实例变量变得非常容易。
在objective-c运行时提供的c语言的api里,你可以为一个对象添加键/值对,然后可以用下面两
个方法来对它进行存取:
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) id objc_getAssociatedObject(id object, const void *key)
如果我们把上述方法的调用包装在属性的自定义getter和setter方法里,对使用我们的api的使用者
来说,我们就实现了一个完全不透明的伪实例变量。
下面这个例子里,我们想要增加一个对象来做为一个view的tag(而UIView已经存在的tag属性只能
接收intergers类型数据,有时候这会成为一个制约的因素)。
我们像下面这样来写"object tag" category的类:
@interface UIView (ObjectTagAdditions) @property (nonatomic, retain) id objectTag; - (UIView *)viewWithObjectTag:(id)object; @end
使用associative references,属性的实现非常直接:
static const char *ObjectTagKey = "ObjectTag"; @implementation UIView (ObjectTagAdditions) @dynamic objectTag; - (id)objectTag { return objc_getAssociatedObject(self, ObjectTagKey); } - (void)setObjectTag:(id)newObjectTag { objc_setAssociatedObject(self, ObjectTagKey, newObjectTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } ...
通过在set方法中指定OBJC_ASSOCIATION_RETAIN_NONATOMIC,我们告诉编译器在运行时retain
这个变量的值。其它可用来指定的标识是:OBJC_ASSOCIATION_ASSIGN
, OBJC_ASSOCIATION_COPY_NONATOMIC
,OBJC_ASSOCIATION_RETAIN
,
OBJC_ASSOCIATION_COPY;你可以根据情况使用。
最后,这里还有一段-viewWithObjectTag:method:递归代码,用来查找有这个objectTag的view:
- (UIView *)viewWithObjectTag:(id)object { // Raise an exception if object is nil if (object == nil) { [NSException raise:NSInternalInconsistencyException format:@"Argument to -viewWithObjectTag: must not be nil"]; } // Recursively search the view hierarchy for the specified objectTag if ([self.objectTag isEqual:object]) { return self; } for (UIView *subview in self.subviews) { UIView *resultView = [subview viewWithObjectTag:object]; if (resultView != nil) { return resultView; } } return nil; }