2011-05-06 48 views
60

在我接受的一个项目中,原作者选择使用objc_setAssociatedObject(),我并不十分清楚它做了什么或者他们为什么决定使用它。什么是objc_setAssociatedObject()以及在什么情况下应该使用它?

我决定查阅它,不幸的是,这些文档对其目的不是非常具有描述性。

objc_setAssociatedObject
设置使用给定的键和关联政策给定对象关联的值。
void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)
参数
object
用于关联的源对象。
key
该协会的关键。
value
与对象的键关联关联的值。通过零来清除现有的关联。
policy
该协会的政策。有关可能的值,请参阅“关联对象行为”。

那么究竟该函数做了什么以及在什么情况下应该使用它?看完后


编辑答案

那么,什么是在下面的代码点?

Device *device = [self.list objectAtIndex:[indexPath row]]; 
DeviceViewController *next = [[DeviceViewController alloc] initWithController:self.controller 
                      device:device 
                       item:self.rootVC.selectedItem]; 
    objc_setAssociatedObject(device, &kDeviceControllerKey, next, OBJC_ASSOCIATION_RETAIN); 

如果设备已经是实例变量,将设备与视图控制器关联的关键点是什么?

回答

30

从参考文献上Objective-C Runtime Reference

您使用Objective-C运行时 功能objc_setAssociatedObject到 使一个物体 和另一之间的关联。该函数需要四个参数: 参数:源对象,密钥, 的值和关联策略 常量。关键是一个空指针。

  • 每个关联的关键字必须是唯一的。一个典型的模式是使用一个静态变量 。
  • 的策略指定的相关联的对象是否被分配,
    保留,或复制,以及是否
    关联被原子或
    非原子制成。该模式是
    类似于属性
    已声明的属性(请参阅“属性
    声明属性”)。您使用 常量(请参阅
    objc_AssociationPolicy和
    关联对象行为)指定 关系的策略。

建立阵列和串

static char overviewKey; 



NSArray *array = 

    [[NSArray alloc] initWithObjects:@"One", @"Two", @"Three", nil]; 

// For the purposes of illustration, use initWithFormat: to ensure 

// the string can be deallocated 

NSString *overview = 

    [[NSString alloc] initWithFormat:@"%@", @"First three numbers"]; 



objc_setAssociatedObject (

    array, 

    &overviewKey, 

    overview, 

    OBJC_ASSOCIATION_RETAIN 

); 



[overview release]; 

// (1) overview valid 

[array release]; 

// (2) overview invalid 

在点1之间的关联,该字符串概述是 仍然有效的,因为 OBJC_ASSOCIATION_RETAIN政策 指定该阵列保留 关联对象。当阵列是 解除分配的,但是,(在点2), 概述被释放,并且因此在这种情况下 也释放。如果您尝试, 例如,登录 概述的价值,你生成一个运行时 例外。

+0

嗨的作者,我被审查文档打算发布类似的答案。当你打败我时,我冒昧地在你的回答中建立超文本链接。希望你不介意。 – JeremyP 2011-05-06 09:41:14

+0

@JeremyP:当然。为此非常感谢。错过了添加链接。感谢您的贡献 – visakh7 2011-05-06 09:42:30

+0

如果可以的话,可以分享一些声誉。 :P – visakh7 2011-05-06 09:43:13

52

objc_setAssociatedObject向每个Objective-C对象添加一个键值存储。它允许您为对象存储额外的状态,而不是反映在其实例变量中。

当你想存储属于对象主要执行以外的事情这真是太方便了。其中一个主要用例是不能添加实例变量的类别。在这里,您使用objc_setAssociatedObject将附加变量附加到self对象。

使用权的关联策略时,主要目的是释放你的对象将被释放。

+0

感谢您的解释。阅读完本文后,我怀疑代码是否以有用的方式使用该函数。我编辑了问题以包含代码。 – Jasarien 2011-05-06 09:59:53

+0

我们不能在这种情况下使用字典保持对象吗? – santhosh 2015-03-23 06:12:56

+0

@ user3127620这就是(语义)什么'objc_setAssociatedObject'。这种机制的优点是它可以在不改变课程的情况下做到这一点(即不需要增加一个ivar)。因此,您可以在框架类或其他您不拥有源代码的情况下执行此操作。 – 2015-03-23 08:57:02

5

要回答你的问题,修订:

中有什么设备用,如果它已经一个实例变量视图控制器关联的地步?

有几个原因,您可能想这样做。

  • Device类没有控制器实例变量或属性,并且您不能更改它或对其进行子类化。你没有源代码。
  • 要与设备对象关联的两个控制器,你不能改变设备类或它的子类。

就我个人而言,我认为很少需要使用低级的Objective-C运行时功能。这看起来像一个代码味道给我。

+0

你这次击败了我:P。 – visakh7 2011-05-06 10:40:33

+2

我想同意你的意见。它有味道。我完全打算正确地做到这一点。感谢您的澄清。 – Jasarien 2011-05-06 10:42:25

24

这里是对象关联的使用情况列表:

之一:实例变量添加到类。一般来说,这项技术是针对advised,但这里是合法使用的example。假设您想为无法修改的对象模拟额外的实例变量(我们正在讨论修改对象本身,即没有子类化)。假设在UIImage上设置标题。

// UIImage-Title.h: 
@interface UIImage(Title) 
@property(nonatomic, copy) NSString *title; 
@end 

// UIImage-Title.m: 
#import <Foundation/Foundation.h> 
#import <objc/runtime.h> 

static char titleKey; 

@implementation UIImage(Title) 
- (NSString *)title 
{ 
    return objc_getAssociatedObject(self, &titleKey); 
} 

- (void)setTitle:(NSString *)title 
{ 
    objc_setAssociatedObject(self, &titleKey, title, OBJC_ASSOCIATION_COPY); 
} 
@end 

此外,here是使用相关联的对象与类别..一个相当复杂的(但真棒)的方式它基本上允许在一个块传递一个选择的,而不是到UIControl


二:动态添加状态信息未包括在与KVO结合它的实例变量的对象。

这个想法是你的对象只在运行时(即动态)获得状态信息。所以这个想法是,虽然你可以将这个状态信息存储在一个实例变量中,但是你将这个信息附加到一个在运行时实例化的对象并将其与另一个对象动态关联的事实上,你突出了事实:这是物体的动态状态。

一个很好的例子说明了这是this库,其中关联对象与KVO通知一起使用。下面是代码的摘录(注意:这个KVO通知不是必须运行的,使得该库中的代码工作..而是为了方便起见作者放在那里),基本上任何注册到此的对象都将通过KVO通知该变化发生的话):

static char BOOLRevealing; 

- (BOOL)isRevealing 
{ 
    return [(NSNumber*)objc_getAssociatedObject(self, &BOOLRevealing) boolValue]; 
} 

- (void)_setRevealing:(BOOL)revealing 
{ 
    [self willChangeValueForKey:@"isRevealing"]; 
    objc_setAssociatedObject(self, &BOOLRevealing, 
     [NSNumber numberWithBool:revealing], OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
    [self didChangeValueForKey:@"isRevealing"]; 
} 

奖金:看看这个discussion/explanation关联对象的由马特·汤普森,精液AFNetworking库

+0

完美!正是我需要的! – 2013-05-01 16:48:50

+0

你的答案中的一个和两个原因是一样的。他们都通过一个类别向对象添加一个实例变量。 – Jasarien 2013-05-01 18:15:58

+0

@Jasarien我的坏..合并他们。 – abbood 2013-05-01 18:36:25

相关问题