关联引用:能够将某个对象作为value通过唯一的key与另一个对象进行关联,作为value的对象可以看作是另一对象的一部分。能够让开发者给使用category的类中添加自定义属性。
关联对象(associated object):在runtime函数中作为关联值(associated value),例如将对象b作为关联对象(或关联值)与对象a以key值进行关联
NSObject a = [[NSObject alloc]init];
NSObject b = [[NSObject alloc]init];
objc_setAssociatedObject(a, key, b, OBJC_ASSOCIATION_ASSIGN);
runtime与关联引用有关的方法
-
创建关联引用
/** * 通过给定的key和关联策略,为给定对象创建一个关联value * @param object 进行关联操作的源对象The source object for the assciation. * @param key 关联引用需要的key值. * @param value 与Key值关联的value,value为nil,可清除已存在的关联 * @param policy关联策略 **/ void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
-
获取关联对象
/** * 按照给定对象和给定key返回关联的value * @param object 关联操作的源对象 * @param key 关联操作的key. * @return 通过key与对象进行关联的value. */ id objc_getAssociatedObject(id object, const void *key)
-
移除关联引用
/** * 移除对象所有的关联引用 * @param object 具有关联引用的对象. * @note 这个函数的目的是为了方便获取给定对象的没有任何关联引用原始状态。 * 不应该用这个函数移除某个value与对象的关联引用,因为这样也会移除这个对 * 象与其它对象的关联引用。通常,应使用objc_setAssociatedObject,传入 * nil的value来清除对象与某个已存在的value的关联引用 */ void objc_removeAssociatedObjects(id object)
关联策略(objc_AssociationPolicy)
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
OBJC_ASSOCIATION_ASSIGN = 0, /**< 指定关联对象的弱引用 */
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< 指定关联对象的非原子性的强引用*/
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /**< 指定关联对象为copy类型并且非原子性*/
OBJC_ASSOCIATION_RETAIN = 01401, /**< 指定关联对象为原子性强引用*/
OBJC_ASSOCIATION_COPY = 01403 /**< 指定关联对象为原子性的copy*/
};
关联引用的使用方式
- 添加私有成员变量
- 给category添加公共属性
- 为KVO创建关联的观察者对象:当在category中使用KVO时,推荐使用自定义的关联对象作为观察者,可以参考文章Objective-C Associated Objects
示例:在category中添加属性
-
.h文件
@interface NSObject (Custom) { // NSString *str0; //使用category的类中不能添加成员变量 } @property (nonatomic, strong) NSString *str1; @end
-
.m文件
#import "NSObject+Custom.h" #import <objc/runtime.h> @implementation NSObject (Custom) @dynamic str1; //这里使用@dynamic告诉编译器在编译期间不要自动创建属性的存取方法,也可以不用写(因为可以对同名的方法进行override) //定义key值,一般为静态char类型,最简便的方式就是用SEL类型作为key值 //static char key; - (void)setStr1:(NSString *)str1 { // objc_setAssociatedObject(self, &key, str1, OBJC_ASSOCIATION_COPY_NONATOMIC); //用SEL代替static char的key objc_setAssociatedObject(self, @selector(str1), str1, OBJC_ASSOCIATION_COPY); } - (NSString *)str1 { // return objc_getAssociatedObject(self, &key); //用SEL类型代替static char的key return objc_getAssociatedObject(self, @selector(str1)); } @end
使用注意
当在category中定义了与class同名的成员时,会category中的成员会覆盖class中的成员,这是因为getter方法会优先寻找category中的属性。