객체 내에서 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.
'Programing' 카테고리의 다른 글
단위 테스트 ASP.NET DataAnnotations 유효성 검사 (0) | 2020.11.17 |
---|---|
jQuery.ready에 정의 된 함수를 전역 적으로 사용하려면 어떻게해야합니까? (0) | 2020.11.17 |
C # 난수 생성기는 스레드 안전합니까? (0) | 2020.11.17 |
문자열에서 숫자를 제거 하시겠습니까? (0) | 2020.11.17 |
주 창을 닫을 때 WPF 앱이 종료되지 않음 (0) | 2020.11.17 |