Programing

객체 내에서 objc_setAssociatedObject / objc_getAssociatedObject를 어떻게 사용합니까?

lottogame 2020. 11. 17. 07:38
반응형

객체 내에서 objc_setAssociatedObject / objc_getAssociatedObject를 어떻게 사용합니까?


setter 메서드에 시뮬레이션 된 인스턴스 변수를 저장하기 위해 범주 구현 내에서 objc_setAssociatedObject / objc_getAssociatedObject를 사용하는 경우 setter 메서드에서 선언 된 변수가 getter 메서드의 범위를 벗어나므로 어떻게 getter 메서드의 키에 액세스 할 수 있습니까?

편집 : 명확히하기 위해 다음 패턴을 사용한다면 setter와 getter 메서드 모두에서 사용할 수 있도록 STRING_KEY를 선언해야합니다.

@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

주소 를 키로 사용할 수 있도록 정적 변수를 선언하십시오 . objc_setAssociatedObject에 대한 호출은 void *를 취하고 메모리 만 낭비하는 NSString의 내용이 아닌 정적 변수의 주소 만 실제로 사용됩니다.

다음을 추가하기 만하면됩니다.

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

나는이 질문이 오래되었다는 것을 알고 있지만 완전성을 위해 언급 할 가치가있는 관련 객체를 사용하는 다른 방법이 있다고 생각합니다. 이 솔루션은 사용 @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

( http://www.tuaw.com/2013/04/10/devjuice-better-objective-c-related-objects/에서 영감을 얻음 )


연결된 저장소 void *키의 경우 다음과 같은 방법이 좋습니다.

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

이렇게하면 실행 파일에 다른 상수 문자열이있는 것을 방지하고 값을 자체 주소로 설정하면 고유 한 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

@interface NSObject (ExampleCategoryWithProperty)

@property (nonatomic, retain) NSArray *laserUnicorns;

@end

.m-file

#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. Why? See 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. 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. 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). For objc_set/getAssociatedObject, all that matters is that the value passed as key is unique within your process/program.

참고URL : https://stackoverflow.com/questions/2846218/how-do-i-use-objc-setassociatedobject-objc-getassociatedobject-inside-an-object

반응형