“关联对象”:可以给某个对象关联许多其他对象,这些对象通过“键”来区分。
存储对象值时,可以指明“存储策略”,用以维护相应的“内存管理语义”。
存储策略由名为objc_AssociationPolicy的枚举所定义:
使用方法:
void objc_setAssociatedObject(id object, void*key, id value, objc_AssociationPolicy policy)
此方法以给定的键和策略为某对象设置关联对象值。
id objc_getAssociatedObject(id object, void*key)
此方法根据给定的键从某对象中获取相应的关联对象值。
void objc_removeAssociatedObjects(id object)
此方法移除指定对象的全部关联对象。
注意事项:
设置关联对象时用的键(key)是个“不透明的指针”,在设置关联对象值时,通常使用静态全局变量做键。
// 示例1
#import "EOCPerson.h"
#import <objc/runtime.h>
static void *kAssociatedObject = @"associatedObject";
EOCPerson *person = [EOCPerson new];
objc_setAssociatedObject(person, kAssociatedObject, @"hello", OBJC_ASSOCIATION_COPY_NONATOMIC);
NSString *associatedStr = objc_getAssociatedObject(person, kAssociatedObject);
NSLog(@"associatedStr : %@",associatedStr);
objc_removeAssociatedObjects(person);
associatedStr = objc_getAssociatedObject(person, kAssociatedObject);
NSLog(@"associatedStr : %@",associatedStr);
输出:
2018-08-12 12:57:26.695315+0800 Demo[28077:1457259] associatedStr : hello
2018-08-12 12:57:32.307315+0800 Demo[28077:1457259] associatedStr : (null)
// 示例2
static void *EOCMyAlertViewKey = @"EOCMyAlertViewKey";
- (void)askUserAQuestion
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Question" message:@"What do you want to do?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Continue", nil];
void (^block) (NSInteger) = ^(NSInteger buttonIndex) {
if (buttonIndex == 0) {
[self doCancel];
} else {
[self doContinue];
}
};
objc_setAssociatedObject(alert, EOCMyAlertViewKey, block, OBJC_ASSOCIATION_COPY);
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
void (^block) (NSInteger) = objc_getAssociatedObject(alertView, EOCMyAlertViewKey);
block(buttonIndex);
}
注意:示例中块可能会捕获某些变量,这也许会造成“保留环”(就是循环引用)。
只有在其他做法不可行时才应选用关联对象,因为这种做法通常会引入难于查找的bug。