我们知道,在 Objective-C 中可以通过 Category 给一个现有的类添加属性,但是却不能添加实例变量。但我们可以通过 Associated Objects 来弥补这一不足。
相关函数
与 Associated Objects 相关的函数主要有三个,我们可以在 runtime 源码的 runtime.h 文件中找到它们的声明:
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);
-objc_setAssociatedObject
用于给对象添加关联对象,传入 nil 则可以移除已有的关联对象;
-objc_getAssociatedObject
用于获取关联对象;
-objc_removeAssociatedObjects
用于移除一个对象的所有关联对象。
key值
一般来说,有以下三种推荐的 key 值:
1、声明 static char kAssociatedObjectKey;
,使用 &kAssociatedObjectKey
作为key
值;
2、声明 static void *kAssociatedObjectKey = &kAssociatedObjectKey;
,使用 kAssociatedObjectKey
作为 key
值;
3、用selector
,使用 getter 方法的名称作为key
值。
三种方式看个人习惯都可以。
关联策略
在给一个对象添加关联对象时有五种关联策略可供选择:
关联策略 | 等价属性 | 说明 |
---|---|---|
OBJC_ASSOCIATION_ASSIGN | @property (assign) | 弱引用关联对象 |
OBJC_ASSOCIATION_RETAIN_NONATOMIC | @property (strong, nonatomic) | 强引用关联对象,且为非原子操作 |
OBJC_ASSOCIATION_COPY_NONATOMIC | @property (copy, nonatomic) | 复制关联对象,且为非原子操作 |
OBJC_ASSOCIATION_RETAIN | @property (strong, atomic) | 强引用关联对象,且为原子操作 |
OBJC_ASSOCIATION_COPY | @property (copy, atomic) | 复制关联对象,且为原子操作 |
具体实现
我将演示用3种key值
@interface UIViewController (AssociatedObjects)
@property (strong, nonatomic) NSString *associatedObject_retain;
@property (copy, nonatomic) NSString *associatedObject_copy;
@property (assign, nonatomic) BOOL associatedObject_assign;
@end
#import "UIViewController+AssociatedObjects.h"
#import "objc/runtime.h"
//声明key值
static char kAssociatedObject_retain_Key;
static void *kAssociatedObject_copy_Key = &kAssociatedObject_copy_Key;
@implementation UIViewController (AssociatedObjects)
- (NSString *)associatedObject_copy {
return objc_getAssociatedObject(self, kAssociatedObject_copy_Key);
}
- (void)setAssociatedObject_copy:(NSString *)associatedObject_copy {
objc_setAssociatedObject(self, kAssociatedObject_copy_Key, associatedObject_copy, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)associatedObject_retain {
return objc_getAssociatedObject(self, &kAssociatedObject_retain_Key);
}
- (void)setAssociatedObject_retain:(NSString *)associatedObject_retain {
objc_setAssociatedObject(self, &kAssociatedObject_retain_Key, associatedObject_retain, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)associatedObject_assign {
return [objc_getAssociatedObject(self, _cmd) boolValue];
}
- (void)setAssociatedObject_assign:(BOOL)associatedObject_assign {
objc_setAssociatedObject(self, @selector(associatedObject_assign), @(associatedObject_assign), OBJC_ASSOCIATION_ASSIGN);
}
@end