カテゴリ実装内でobjc_setAssociatedObject/objc_getAssociatedObjectを使用してシミュレートされたインスタンス変数をセッターメソッドに格納する場合、セッターメソッドで宣言された変数はゲッターメソッドのスコープ外になるため、ゲッターメソッドでキーにアクセスするにはどうすればよいですか?
編集:次のパターンを使用する場合、セッターメソッドとゲッターメソッドの両方でSTRING_KEYを使用できるようにするには、どこで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
addressをキーとして使用できるように、静的変数を宣言します。 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-associated-objects/ に触発された)
関連ストレージの場合void *
キー、私はそれを行うこの方法が好きです:
static void * const kMyAssociatedStorageKey = (void*)&kMyAssociatedStorageKey;
これにより、実行可能ファイルに別の定数文字列が含まれることが回避され、その値をそれ自体のアドレスに設定することにより、優れた一意性とconst
動作が得られます(したがって、キーの値を変更します)、余分な不要なエクスポートシンボルはありません。
ソースファイルのトップレベルで静的(コンパイル単位スコープ)変数を宣言します。次のような意味のあるものにするのに役立つかもしれません:
static NSString *MYSimulatedString = @"MYSimulatedString";
かなり近いです。完全な例を次に示します。
。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
_
通常のプロパティのように-ドット表記でアクセス可能
_NSObject *myObject = [NSObject new];
myObject.laserUnicorns = @[@"dipwit", @"dipshit"];
NSLog(@"Laser unicorns: %@", myObject.laserUnicorns);
_
簡単な構文
または、静的ポインターを作成する代わりに@selector(nameOfGetter)
を使用できます。どうして? https://stackoverflow.com/a/16020927/202451 を参照してください。例:
_- (NSArray *)laserUnicorns {
return objc_getAssociatedObject(self, @selector(laserUnicorns));
}
- (void)setLaserUnicorns:(NSArray *)unicorns {
objc_setAssociatedObject(self, @selector(laserUnicorns), unicorns, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
_
受け入れられた答えはすでに正しかったのですが、説明を追加したいと思います。「キー」のポイントは、偶発的な衝突を起こさない一意の(プロセス/プログラムごとの)識別子を取得することです。
キーがNSUInteger
として宣言されていると想像してください。多くの人が0
、1
、または42
などの標準値を使用します。特に、ライブラリまたはフレームワークを使用している場合、衝突が発生する可能性があります。
その代わり、巧妙なAppleエンジニアは、変数を宣言してその変数へのポインターを渡すことを意図して、キーがポインターであると宣言するという考えを持っていましたキー:リンカはその変数にアプリケーション内で一意のアドレスを割り当てるため、一意の衝突のない値を取得することが保証されます。
実際、任意の値を渡すことができますが、ポインターは逆参照されません(テストしました)。したがって、(void *)0
または(void *)42
をキーとして渡すことは機能しますが、それは良い考えではありません(したがって、そうしないでください)。 objc_set/getAssociatedObject
の場合、重要なのは、キーとして渡された値がプロセス/プログラム内で一意であることだけです。