利用 OC 语言的动态性,借助运行时(runtime)的功能,咱们能够为已存在的实例对象增长实例变量,这个功能叫作关联引用。编程
objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,id _Nullable value, objc_AssociationPolicy policy)
该方法为对象 object 添加以 key 指定的地址做为关键字、以value为值的关联引用,第四个参数policy指定关联引用的存储策略。数组
objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key) OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);
返回 object 以 Key 为关键字的关联对象,若是没有关联对象,则返回 nil安全
objc_removeAssociatedObjects(id _Nonnull object) OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);
断开关联多线程
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) { OBJC_ASSOCIATION_ASSIGN = 0, /*弱引用对象保存对象*/ OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /*强引用对象保存对象,非原子性*/ OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /*复制一份原对象,非原子性*/ OBJC_ASSOCIATION_RETAIN = 01401, /*引用对象保存对象,默认原子性,多线程安全 */ OBJC_ASSOCIATION_COPY = 01403 /*复制一份原对象,默认原子性,多线程安全*/ };
假设咱们为 NSArray 增长了一个新的随机取元素的方法,而且取得的元素不能够连续相同,咱们利用范畴(category)为 NSArray 扩展一个方法。dom
NSArray+Random.hui
#import <Foundation/Foundation.h> @interface NSArray (Random) - (id)anyOne; @end
NSArray+Random.m线程
#import "NSArray+Random.h" #import <objc/runtime.h> @implementation NSArray (Random) static char prevKey; - (id)anyOne { id item; NSUInteger count = [self count]; if (count == 0) { return nil; }else if(count == 1){ return [self lastObject]; }else{ id prev = objc_getAssociatedObject(self, &prevKey);//获取关联对象所引用的值,初次使用返回 nil NSUInteger index = random()%count; item = self[index]; if (item == prev) {//索引相同状况下,取下一个元素,若该索引是数组最后一个,则取第一个值 if (++index >= count) { index = 0; } item = self[index]; } printf("item:%s,prevItem:%s\n",[item UTF8String],[prev UTF8String]); } objc_setAssociatedObject(self, &prevKey, item, OBJC_ASSOCIATION_RETAIN);//存储最后返回的对象 return item; }
main.mcode
#import <UIKit/UIKit.h> #import "AppDelegate.h" #import "NSArray+Random.h" int main(int argc, char * argv[]) { id arr1 = @[@"1",@"2",@"3",@"4",@"5",@"6",@"7"]; id arr2 = @[@"a",@"b",@"c",@"d",@"e",@"f",@"g"]; for (int i=0; i<15; i++) { printf("arr1:%s,arr2:%s\n",[[arr1 anyOne] UTF8String], [[arr2 anyOne] UTF8String]); } @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
item:2,prevItem:(null) item:e,prevItem:(null) arr1:2,arr2:e item:3,prevItem:2 item:f,prevItem:e arr1:3,arr2:f item:2,prevItem:3 item:d,prevItem:f arr1:2,arr2:d item:4,prevItem:2 item:c,prevItem:d arr1:4,arr2:c item:2,prevItem:4 item:d,prevItem:c arr1:2,arr2:d item:3,prevItem:2 item:f,prevItem:d arr1:3,arr2:f item:7,prevItem:3 item:e,prevItem:f arr1:7,arr2:e item:1,prevItem:7 item:a,prevItem:e arr1:1,arr2:a
综合使用关联引用和范畴,能够大大加强 OC 编程的灵活性,但也不能滥用,会致使程序很差理解。对象