- 可以通过“关联对象”机制来把两个对象连起来
- 定义关联对象时可指定内存管理语义,用以模仿定义属性时所采用的“拥有关系”与“非拥有关系”
- 只有在其他做法不可行时才应选用关联对象,因为这种做法通常会引入难于查找的 bug
目的:需要在对象中存放相关信息,方法一,从对象所属的类中继承一个子类,然后改用这个子类对象。
方法二:关联对象(Associated Object),对象通过“键”来区分。
可以把某对象想象成NSDictionary,把关联到对象上调用[object setObject:value forKey:key] 与 [object objectForKey:key]方法。但是设置关联对象那个时用的键(key)是个“不透明的指针“(opaque pointer),
如果在两个键上调用”isEqual“方法返回值是 YES, 那么NSDictionary就认为两者相等;然而设置关联对象时,二者必须是完全相同的指针才行。鉴于此,在设置关联对象值时,通常使用静态全局变量做键。
下列方法管理关联对象:
void objc_setAssociatedObject (id object, void*key, id value, objc_AssociationPolicy policy)
此方法以给定的键和策略为某对象设置关联对象值
id objc_getAssociatedObject(id object, void*key)
此方法根据给定的键从某对象中获取相应的关联对象值
void objc_removeAssociatedObjects(id object)
此方法移除指定对象的全部关联对象
例子:UIAlertView 类,警告信息,当用户按下按钮关闭该视图时,需要用委托协议(delegate protocol)在处理此动作,但是要想设置好这个委托机制,就得把创建警告视图和处理按钮动作的代码分开。比兔使用UIAlertView 时,一般都会这么写:
- (void)askUserAQuestion { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Question" message:@"What do you want to do?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTiles:@"Continue",nil]; [alert show];}// UIAlertViewDelegate protocol method- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{ if (buttoIndex == 0) { [self doCancel]; } else { [self doContinue]; }}
如果想在同一个类里处理多个警告信息视图,那么代码就会变得更为复杂,必须在delegate方法中检查传入的 alertView 参数
可以使用关联对象 在创建警告视图的时候直接把处理每个按钮的逻辑都写好:创建完警告视图之后,设定一个与之关联的“块” block,等到执行 delegate 方法是再将其读出来,代码如下
#importstatic void *EOCMyAlertViewKey = "EOCMyAlertViewKey"; - (void)askUserAQuestion { UIAlertView *alert = [[UIAlertViewalloc] 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_setAssociateObject(alert, EOCMyAlertViewKey, block, BJC_ASSOCIATION_COPY); [alert show];}// UIAlertViewDelegate protocol method 关联类型等效的@property 属性为- (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{ void (^block) (NSInteger) = objc_getAssociateObject(alertView, EOCMyAlertViewKey); block(buttonIndex);}
注意:块可能要捕获 (capture)某些变量,这也许会造成“保留环)(retain cycle)