什么是 objc_setAssociatedObject() 以及在什么情况下应该使用它?

发布于 2024-11-05 14:10:27 字数 1095 浏览 0 评论 0原文

在我承担的一个项目中,原作者选择使用 objc_setAssociatedObject(),但我并不 100% 清楚它的作用或他们决定使用它的原因。

我决定查找它,不幸的是,文档并没有很好地描述其用途。

objc_setAssociatedObject
使用给定键和关联策略为给定对象设置关联值。
void objc_setAssociatedObject(id 对象, void *key, id 值, objc_AssociationPolicy 策略)
参数
对象
关联的源对象。
密钥
协会的钥匙。

与对象的键关联的值。传递 nil 来清除现有关联。
政策
协会的政策。有关可能的值,请参阅“关联对象行为”。

那么这个函数到底有什么作用以及在什么情况下应该使用它呢?


阅读答案后进行编辑

那么下面的代码有什么意义呢?

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);

如果设备已经是实例变量,那么将设​​备与视图控制器关联起来有什么意义呢?

In a project I have taken on, the original author has opted to use objc_setAssociatedObject() and I'm not 100% clear what it does or why they decided to use it.

I decided to look it up and, unfortunately, the docs aren't very descriptive about its purpose.

objc_setAssociatedObject
Sets an associated value for a given object using a given key and association policy.
void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)
Parameters
object
The source object for the association.
key
The key for the association.
value
The value to associate with the key key for object. Pass nil to clear an existing association.
policy
The policy for the association. For possible values, see “Associative Object Behaviors.”

So what exactly does this function do and in what cases should it be used?


Edit after reading answers

So what is the point in the following code?

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);

What is the point in associating the device with the view controller if it's already an instance variable?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

Hello爱情风 2024-11-12 14:10:27

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

当您想要存储属于主实现之外的对象的内容时,这确实很方便。主要用例之一是无法添加实例变量的类别。在这里,您使用 objc_setAssociatedObject 将附加变量附加到 self 对象。

当使用正确的关联策略时,当主对象被释放时,您的对象将被释放。

objc_setAssociatedObject adds a key value store to each Objective-C object. It lets you store additional state for the object, not reflected in its instance variables.

It's really convenient when you want to store things belonging to an object outside of the main implementation. One of the main use cases is in categories where you cannot add instance variables. Here you use objc_setAssociatedObject to attach your additional variables to the self object.

When using the right association policy your objects will be released when the main object is deallocated.

撕心裂肺的伤痛 2024-11-12 14:10:27

来自 目标的参考文档-C 运行时参考

您使用 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 点),
概述已发布,因此在此
案件也被解除分配。如果你尝试这样做,
例如,记录以下值
概述,您生成一个运行时
异常。

From the reference documents on Objective-C Runtime Reference:

You use the Objective-C runtime
function objc_setAssociatedObject to
make an association between one object
and another. The function takes four
parameters: the source object, a key,
the value, and an association policy
constant. The key is a void pointer.

  • The key for each association must be unique. A typical pattern is to
    use a static variable.
  • The policy specifies whether the associated object is assigned,
    retained, or copied, and whether the
    association is be made atomically or
    non-atomically. This pattern is
    similar to that of the attributes of
    a declared property (see “Property
    Declaration Attributes”). You specify
    the policy for the relationship using
    a constant (see
    objc_AssociationPolicy and
    Associative Object Behaviors).

Establishing an association between an array and a string

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

At point 1, the string overview is
still valid because the
OBJC_ASSOCIATION_RETAIN policy
specifies that the array retains the
associated object. When the array is
deallocated, however (at point 2),
overview is released and so in this
case also deallocated. If you try to,
for example, log the value of
overview, you generate a runtime
exception.

抚笙 2024-11-12 14:10:27

以下是对象关联的用例列表:

一个: 将实例变量添加到类别。一般来说,不建议使用这种技术,但这里有一个合法使用的示例。假设您想要为无法修改的对象模拟附加实例变量(我们正在讨论修改对象本身,即没有子类化)。假设在 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

另外,这里是一种使用类别关联对象的非常复杂(但很棒)的方法..它基本上允许您通过在块中而不是 UIControl 的选择器中。


:结合KVO动态地给未被其实例变量覆盖的对象添加状态信息。

这个想法是你的对象仅在运行时(即动态地)获取状态信息。因此,我们的想法是,虽然您可以将此状态信息存储在实例变量中,但事实上,您将此信息附加到在运行时实例化的对象中并将其与另一个对象动态关联,您强调了这样一个事实:物体的动态状态。

说明这一点的一个很好的例子是这个库,其中关联对象与 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"];
}

奖励:看看这个讨论/解释< /a> 关联对象,作者:Mattt Thompson,开创性 AFNetworking 库的作者

Here is a list of use cases for object associations:

one: To add instance variables to categories. In general this technique is advised against, but here is an example of a legitimate use. Let's say you want to simulate additional instance variables for objects you cannot modify (we are talking about modifying the object itself, ie without subclassing). Let's say setting a title on a 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

Also, here is a pretty complex (but awesome) way of using associated objects with categories.. it basically allows you to pass in a block instead of a selector to a UIControl.


two: Dynamically adding state information to an object not covered by its instance variables in conjunction with KVO.

The idea is that your object gains state information only during runtime (ie dynamically). So the idea is that although you can store this state info in an instance variable, the fact that you're attaching this info into a an object instantiated at runtime and dynamically associating it with the other object, you are highlighting the fact that this is a dynamic state of the object.

One excellent example that illustrates this is this library, in which associative objects are used with KVO notifications. Here is an excerpt of the code (note: this KVO notification isn't necessary to run make the code in that library work.. rather it's put there by the author for convenience, basically any object that registers to this will be notified via KVO that changes have happened to it):

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"];
}

bonus: take a look at this discussion/explanation of associated objects by Mattt Thompson, author of the seminal AFNetworking library

記柔刀 2024-11-12 14:10:27

回答您修改后的问题:

如果设备已经是实例变量,那么将设​​备与视图控制器关联起来有什么意义?

您可能想要这样做的原因有多种。

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

就我个人而言,我认为很少需要使用低级 Objective-C 运行时函数。对我来说这看起来像是代码味道。

To answer your revised question:

What is the point in associating the device with the view controller if it's already an instance variable?

There are several reasons why you might want to do this.

  • the Device class doesn't have a controller instance variable, or property and you can't change it or subclass it e.g. you don't have the source code.
  • you want two controllers associated with the device object and you can't change the device class or subclass it.

Personally, I think it is very rare to need to use low level Objective-C runtime functions. This looks like a code smell to me.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文