23

関連付けられたオブジェクト (iOS 4 および OSX 10.6 以降で利用可能な Objective-C ランタイム機能) を使用する場合、実行時にオブジェクトを格納および取得するためのキーを定義する必要があります。

典型的な使用法は、次のようにキーを定義することです

static char const * const ObjectTagKey = "ObjectTag";

次に、 is を使用してオブジェクトを保存します

objc_setAssociatedObject(self, ObjectTagKey, newObjectTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

そしてそれを取り戻す

objc_getAssociatedObject(self, ObjectTagKey);

(例はhttp://oleb.net/blog/2011/05/faking-ivars-in-objc-categories-with-associative-references/ )

追加の変数の宣言を伴わない、関連付けられたオブジェクト キーを定義するよりクリーンな方法はありますか?

4

3 に答える 3

50

Erica Sadun によるこのブログ エントリ(クレジットはGwynne Raskindに送られます) によると、あります。

objc_getAssociatedObjectobjc_getAssociatedObjectオブジェクトを保存するためのキーが必要です。voidこのようなキーは、定数ポインターである必要があります。したがって、最終的に必要なのは、時間の経過とともに変化しない固定アドレスだけです。

この@selector実装は、固定アドレスを使用するため、ほぼ必要なものを提供することがわかりました。

したがって、キー宣言を削除して、プロパティのセレクター アドレスを使用するだけです。

したがって、実行時に次のようなプロパティを関連付けている場合

@property (nonatomic, retain) id anAssociatedObject;

次のようなゲッター/セッターの動的実装を提供できます

- (void)setAnAssociatedObject:(id)newAssociatedObject {
     objc_setAssociatedObject(self, @selector(anAssociatedObject), newAssociatedObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (id)anAssociatedObject {
    return objc_getAssociatedObject(self, @selector(anAssociatedObject));
}

関連するすべてのオブジェクトに追加の静的変数キーを定義するよりも、非常にきちんとしていて間違いなくクリーンです。

これは安全ですか?

これは実装に依存するため、正当な質問は次のとおりです。簡単に壊れますか? ブログ記事引用

そのためには、Apple はおそらくまったく新しい ABI を実装する必要があるでしょう。

これらの言葉が真実であるとすれば、それはかなり安全です。

于 2013-04-15T17:12:22.390 に答える
5

@Gabriele Petronella が議論したアイデアのわずかなバリエーションは、辞書をすべてのオブジェクトに関連付けることです。

//NSObject+ADDLAssociatedDictionary.h

#import <Foundation/Foundation.h>

@interface NSObject (ADDLAssociatedDictionary)
- (void)addl_setAssociatedObject:(id)object forKey:(id<NSCopying>)key;
- (id)addl_associatedObjectForKey:(id<NSCopying>)key;
@end

//NSObject+ADDLAssociatedDictionary.m

#import <objc/runtime.h>

@interface NSObject (ADDLAssociatedDictionaryInternal)
- (NSMutableDictionary *)addl_associatedDictionary;
@end

@implementation NSObject (ADDLAssociatedDictionary)

- (void)addl_setAssociatedObject:(id)object forKey:(id<NSCopying>)key
{
    if (object) {
        self.addl_associatedDictionary[key] = object;
    } else {
        [self.addl_associatedDictionary removeObjectForKey:key];
    }
}
- (id)addl_associatedObjectForKey:(id<NSCopying>)key
{
    return self.addl_associatedDictionary[key];
}

@end

@implementation NSObject (ADDLAssociatedDictionaryInternal)
const char addl_associatedDictionaryAssociatedObjectKey;
- (NSMutableDictionary *)addl_associatedDictionaryPrimitive
{
    return objc_getAssociatedObject(self, &addl_associatedDictionaryAssociatedObjectKey);
}
- (void)addl_setAssociatedDictionaryPrimitive:(NSMutableDictionary *)associatedDictionary
{
    objc_setAssociatedObject(self, &addl_associatedDictionaryAssociatedObjectKey, associatedDictionary, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSMutableDictionary *)addl_generateAssociatedDictionary
{
    NSMutableDictionary *associatedDictionary = [[NSMutableDictionary alloc] init];
    [self addl_setAssociatedDictionaryPrimitive:associatedDictionary];
    return associatedDictionary;
}

- (NSMutableDictionary *)addl_associatedDictionary
{
    NSMutableDictionary *res = nil;

    @synchronized(self) {
        if (!(res = [self addl_associatedDictionaryPrimitive])) {
            res = [self addl_generateAssociatedDictionary];
        }
    }

    return res;
}
@end

次に、NSObject のサブクラス Derived のカテゴリで

//Derived+Additions.h

#import "Derived.h"

@interface Derived (Additions)
@property (nonatomic) id anAssociatedObject;
@end

//Derived+Additions.m

#import "NSObject+ADDLAssociatedDictionary.h"

@implementation Derived (Additions)
- (void)setAnAssociatedObject:(id)anAssociatedObject
{
    [self addl_setAssociatedObject:anAssociatedObject forKey:NSStringFromSelector(@selector(anAssociatedObject))];
}
- (id)anAssociatedObject
{
    return [self addl_associatedObjectForKey:NSStringFromSelector(@selector(anAssociatedObject))];
}
@end

関連付けられたディクショナリ アプローチの一般的な利点の 1 つは、実行時に生成されるキーのオブジェクトを設定できることによる柔軟性の向上です。

使うだけのメリット

NSStringFromSelector(@selector(anAssociatedObject))

つまり、常に受け入れ可能な辞書キーとなるセレクターの表現NSStringFromSelectorを提供することが保証されています。NSStringその結果、ABI の変更についてまったく心配する必要はありません (合理的な懸念ではないと思いますが)。

于 2013-04-16T04:16:42.947 に答える