web-dev-qa-db-ja.com

NSDictionaryでキーとしてクラスを使用する

いくつかのConverterクラスから継承するコンバーター/作動オブジェクトのディクショナリーを維持するコンテキスト「ファクトリー」を書いています。このクラスにはメソッドがあります:

- (Class)classResponsibility

または、StringConverterクラスがメソッドを次のように実装するような類似のもの:

- (Class)classResponsibility {
    return [NSString class];
}

次に、そのコンバーターを辞書に格納するために、私は次のようなことを望んでいました:

[converters setValue:stringConverter forKey:[stringConverter classResponsibility]];

しかし、コンパイラーは、型「Class」がsetValue:forKey:メソッドの引数2の無効なパラメーター型であることを報告します。キーをクラスの名前( "NSString")として設定することは避けたかったのですが、それが最善の解決策である場合は、それを使用します。

37
Craig Otis

NSStringsのみをキーとして取るsetValue:forKey:を使用しています。代わりにsetObject:forKey:を使用する必要があります。クラスオブジェクト(クラスオブジェクトへのポインタはClass型として渡すことができます)は本格的なObjective-Cオブジェクトです(クラスオブジェクトはメタクラスのインスタンスであり、クラスオブジェクトですべてのNSObjectメソッドを使用できます。メタクラスの詳細については here )を参照してください。そのため、オブジェクトが使用される場所ならどこでも使用できます。

辞書のキーのもう1つの要件は、それらがコピーをサポートすることです(つまり、copyWithZone:メソッドを持っています。クラスオブジェクトはこのメソッドをサポートしていますか?実際にはサポートしています。NSObjectクラスは、を定義します) class method+copyWithZone:、その documentation は、「NSDictionaryオブジェクトへのキーとしてクラスオブジェクトを使用できるようにする」ことを明示的に示しています。あなたの質問に答えてください。

99
Skirwan

他のオプションは、[NSValue valueWithNonretainedObject:yourObjectHere]を使用して、文字列以外のものからキーを構築することです。私は同様の問題に遭遇し、CoreDataオブジェクトをキーとして使用し、他の何かを値として使用したいと考えました。このNSValueメソッドは完璧に機能し、私はそれが本来の意図であったと信じています。元の値に戻すには、nonretainedObjectValueを呼び出します。

30
Sean

_-setValue:forKey:_は、2番目のパラメーターとしてNSStringを取るように文書化されています。 NSStringFromClass()およびNSClassFromString()をアダプターとして使用する必要があります。

4
user23743

ClassオブジェクトはNSDictionaryで完全に適切なキーを作成しますが、NSDictionaryに基づいてモデル化されたNSMapTableについて言及する価値はありますが、キーや値として使用するのに適したオブジェクトの種類に関してより柔軟性があります documented 弱参照と任意のポインタをサポートします。

3
Tom M

SetValue:forKey:ではなくsetObject:forKey:メソッドを探していました。 setObject:forKey:のメソッドシグネチャは、(id)を両方のパラメータータイプとして受け入れ、はるかに適しています。

3
Craig Otis

私はちょうど同じエラーメッセージで同様の状況を切り出しました:

[tempDictionary setObject:someDictionary forKey:someClass];

私がしたことは、NSCopyingsomeClassプロトコルを実装することだけでした。

- (id)copyWithZone:(NSZone *)zone
{
    id copy = [[[self class] allocWithZone:zone] init];
    [copy setId:[self id]];
    [copy setTitle:[self title]];
    return copy;
}

キーとして使用するためにsomeClassのコピーが作成されていたことが起こっていたと思いますが、私のオブジェクトはそれ自体をコピーする方法を知りませんでした(NSObjectから派生)スーパークラスにcopyWithZoneがありませんでした)はげました。

私のアプローチで見つけた1つのことは、オブジェクトをキーとして使用することです。オブジェクトが既にインスタンス化されていない限り、私は常にallKeysを呼び出すか、ディクショナリを列挙するだけです。

[これを書いてから、クラスをキーなどとして保存したいと思います。 SOを検索しているときに答えが見つかれば、多くの時間を節約できたので、これはそのままにしておきます。その時、私はこのようなものを見つけませんでした。]

1
bbrown

次のように、クラスをNSDictionaryのキーとして使用できます。

@{
    (id)[MyClass1 class] : @1,
    (id)[MyClass2 class] : @2,
    (id)[MyClass3 class] : @3,
    (id)[MyClass4 class] : @4,
};

または次のようにも:

@{
    MyClass1.self : @1,
    MyClass2.self : @2,
    MyClass3.self : @3,
    MyClass4.self : @4,
};
0
k06a