简体   繁体   English

如何在对象中使用objc_setAssociatedObject / objc_getAssociatedObject?

[英]How do I use objc_setAssociatedObject/objc_getAssociatedObject inside an object?

If I use objc_setAssociatedObject/objc_getAssociatedObject inside a category implementation to store a simulated instance variable in a setter method, how would I access the key in the getter method since any variables declared in the setter method would be outside the scope of the getter method? 如果我在类别实现中使用objc_setAssociatedObject / objc_getAssociatedObject将模拟实例变量存储在setter方法中,那么我将如何访问getter方法中的键,因为setter方法中声明的任何变量都不在getter方法的范围内?

Edit: To clarify, if I were to use the following pattern, where should I declare STRING_KEY so that I could use it in both the setter and the getter method. 编辑:为了澄清,如果我使用以下模式,我应该在哪里声明STRING_KEY,以便我可以在setter和getter方法中使用它。

@interface NSView (simulateVar)
-(void)setSimualtedString:(NSString *)myString;
-(NSString *)simulatedString;
@end

@implementation NSView (simulateVar)

-(void)setSimualtedString: (NSString *)myString
{
    objc_setAssociatedObject(self, &STRING_KEY, myString, OBJC_ASSOCIATION_RETAIN);
}

-(NSString *)simulatedString
{
    return (NSString *)objc_getAssociatedObject(self, &STRING_KEY);
}

@end

Declare a static variable so that you can use its address as the key. 声明一个静态变量,以便您可以使用其地址作为键。 The call to objc_setAssociatedObject takes a void* and only the address of your static variable is actually used, not the contents of a NSString... that is only wasting memory. 对objc_setAssociatedObject的调用采用void *,实际只使用静态变量的地址,而不是NSString的内容......只是浪费内存。

You just need to add: 你只需要添加:

static char STRING_KEY; // global 0 initialization is fine here, no 
                        // need to change it since the value of the
                        // variable is not used, just the address

I know that this question is quit old but I think for completeness there is another way how to use associated objects worth mentioning. 我知道这个问题已经过时了,但我认为完整性还有另一种方法可以使用值得一提的相关对象。 This solution utilizes @selector and therefore there is no need for any extra variable or constant. 该解决方案使用@selector ,因此不需要任何额外的变量或常量。

@interface NSObject (CategoryWithProperty)

@property (nonatomic, strong) NSObject *property;

@end

@implementation NSObject (CategoryWithProperty)

- (NSObject *)property {
    return objc_getAssociatedObject(self, @selector(property));
}

- (void)setProperty:(NSObject *)value {
    objc_setAssociatedObject(self, @selector(property), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

(inspired by http://www.tuaw.com/2013/04/10/devjuice-better-objective-c-associated-objects/ ) (受http://www.tuaw.com/2013/04/10/devjuice-better-objective-c-associated-objects/启发)

For associated storage void * keys, I like this way of doing it: 对于关联存储void *键,我喜欢这样做:

static void * const kMyAssociatedStorageKey = (void*)&kMyAssociatedStorageKey; 

This avoids having another constant string in the executable, and by setting its value to the address of itself, you get good uniquing, and const behavior (so you'll nominally get a compiler complaint if you do something that would change the value of the key), without any extra unnecessary exported symbols. 这避免了在可执行文件中有另一个常量字符串,并通过将其值设置为自身的地址,您可以获得良好的单一性和const行为(因此,如果您执行某些会改变其值的事情,您将在名义上获得编译器投诉键),没有任何额外的不必要的导出符号。

Declare a static (compilation unit-scope) variable at the top level of the source file. 在源文件的顶级声明一个静态(编译单元范围)变量。 It may help to make it meaningful, something like this: 它可能有助于使其有意义,如下所示:

static NSString *MYSimulatedString = @"MYSimulatedString";

Quite close. 相当接近。 Here is a full example. 这是一个完整的例子。

.h-file .H文件

@interface NSObject (ExampleCategoryWithProperty)

@property (nonatomic, retain) NSArray *laserUnicorns;

@end

.m-file .M文件

#import <objc/runtime.h>

static void * LaserUnicornsPropertyKey = &LaserUnicornsPropertyKey;

@implementation NSObject (ExampleCategoryWithProperty)

- (NSArray *)laserUnicorns {
    return objc_getAssociatedObject(self, LaserUnicornsPropertyKey);
}

- (void)setLaserUnicorns:(NSArray *)unicorns {
    objc_setAssociatedObject(self, LaserUnicornsPropertyKey, unicorns, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
}

@end

Just like a normal property - accessible with dot-notation 就像一个普通的财产 - 可用点符号访问

NSObject *myObject = [NSObject new];
myObject.laserUnicorns = @[@"dipwit", @"dipshit"];
NSLog(@"Laser unicorns: %@", myObject.laserUnicorns);

Easier syntax 语法更简单

Alternatively you could use @selector(nameOfGetter) instead of creating a static pointer. 或者,您可以使用@selector(nameOfGetter)而不是创建静态指针。 Why? 为什么? See https://stackoverflow.com/a/16020927/202451 . 请参阅https://stackoverflow.com/a/16020927/202451 Example: 例:

- (NSArray *)laserUnicorns {
    return objc_getAssociatedObject(self, @selector(laserUnicorns));
}

- (void)setLaserUnicorns:(NSArray *)unicorns {
    objc_setAssociatedObject(self, @selector(laserUnicorns), unicorns, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
}

The accepted answer already got it right, but I'd like to add an explanation: the point of the "key" is to get a unique (per process/program) identifier that will not have any accidental collisions. 已接受的答案已经正确,但我想补充说明:“关键”的要点是获得一个不会发生意外碰撞的唯一(每个进程/程序)标识符。

Imagine the key being declared as NSUInteger : lots of people would use standard values like 0 , 1 or 42 . 试想一下,关键被宣布为NSUInteger :很多人会使用标准值一样0142 Especially if you're using some library or framework, collisions are likely. 特别是如果您使用某些库或框架,可能会发生冲突。

So instead, some clever Apple engineer had the idea to declare the key to be a pointer with the intent that you declare a variable and pass the pointer to that variable as a key. 因此,一些聪明的Apple工程师有想法将密钥声明为指针,其意图是声明变量并将指针作为键传递给该变量 The linker will assign that variable an address that is unique within your application and so you are guaranteed to get a unique, collision free value. 链接器将为该变量分配一个在您的应用程序中唯一的地址,因此您可以保证获得唯一的无冲突值。

In fact, you can pass any value you like, the pointer is not dereferenced (I've tested that). 实际上,你可以传递你喜欢的任何值,指针不会被解引用(我已经测试过了)。 So passing (void *)0 or (void *)42 as the key does work, although it's not a good idea (so please don't do that). 所以传递(void *)0(void *)42作为键确实有用,虽然这不是一个好主意(所以请不要这样做)。 For objc_set/getAssociatedObject , all that matters is that the value passed as key is unique within your process/program. 对于objc_set/getAssociatedObject ,重要的是作为键传递的值在您的进程/程序中是唯一的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何存储非id类型变量使用objc_getAssociatedObject / objc_setAssociatedObject? - How to store not id type variable use a objc_getAssociatedObject/objc_setAssociatedObject? `objc_setAssociatedObject` 和 `objc_getAssociatedObject` 不匹配 - `objc_setAssociatedObject` and `objc_getAssociatedObject` isn't match 任何与objc_setAssociatedObject和objc_getAssociatedObject的陷阱? - Any gotchas with objc_setAssociatedObject and objc_getAssociatedObject? objc_setAssociatedObject / objc_getAssociatedObject的C ++等效项是什么? - What's the C++ equivalent of the objc_setAssociatedObject/objc_getAssociatedObject? 对类对象使用objc_setAssociatedObject是否正确? - Is it correct to use objc_setAssociatedObject for class object? 如何将选择器(SEL)与objc_setAssociatedObject一起使用? - How to use selector (SEL) with objc_setAssociatedObject? objc_getAssociatedObject返回null - objc_getAssociatedObject returning null objc_setAssociatedObject在iOS中不可用吗? - Is objc_setAssociatedObject not available in iOS? if(objc_getAssociatedObject(self,&Key))对nil对象返回true - if(objc_getAssociatedObject(self, &Key)) return true for nil object 理解 objc_setAssociatedObject 中的 UnsafeRawPointer - Understanding UnsafeRawPointer in objc_setAssociatedObject
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM