1

私はこのコード参照を理解しようとしました:Cocoa:列挙型キーを持つ辞書?

+ (NSValue*)valueWithReference:(id)target
{
    return [NSValue valueWithBytes:&target objCType:@encode(id*)];
}

と、

[table setObject:anObject forKey:[NSValue valueWithReference:keyObject]];

しかし、それは何か良くない感じがします。何かお勧めはありますか?

4

3 に答える 3

9

あなたは絶対に正しいです、それは良くありません。

1 つは、間違った型 (@encode(id)ではなくである必要があります@encode(id*)) をエンコードしていますが、ほとんどの場合、これは大きな問題にはなりません。

より大きな問題は、これがメモリ管理を完全に無視することです。オブジェクトは保持またはコピーされません。他のコードがそれを解放すると、それが消えるだけで、辞書のキーはガベージへのボックス化されたポインターになるか、まったく別のオブジェクトになります。これは基本的に、世界で最も先進的なダングリング ポインターです。

2 つの適切なオプションがあります。

  1. クラスに NSCopying を追加するか、コピー可能なサブクラスを作成することができます。

    • このオプションは、意味のあるコピーが可能なオブジェクトに対してのみ機能します。これはほとんどのクラスですが、必ずしもすべてではありません (たとえば、複数のオブジェクトが同じ入力ストリームを表すのは良くない場合があります)。
    • コピーを実装することは、理にかなっているクラスであっても苦痛になる可能性があります — それ自体は難しくありませんが、ちょっと面倒です
  2. 代わりにCFDictionary APIを使用して辞書を作成できます。Core Foundation 型には一般的なコピー関数がないため、CFDictionary はデフォルトでそのキーを保持するだけです (ただし、その動作は好きなようにカスタマイズできます)。ただし、CFDictionary は NSDictionary とブリッジされた通話料無料でもあります。つまり、 aCFDictionaryRefNSDictionary*(またはNSMutableDictionary*) にキャストするだけで、他の NSDictionary と同じように扱うことができます。

    • これは、キーとして使用しているオブジェクトがディクショナリ内にある間は変更してはならないことを意味します (少なくともそのhash値に影響を与える方法で)。これが起こらないようにすることが、NSDictionary が通常そのキーをコピーしたい理由です。
于 2010-08-18T06:06:32.613 に答える
1

あとで参考までに。

これで、さらにいくつかのオプションがあることがわかりました。

  1. NSCopyingプロトコルでメソッドをオーバーライドし、selfそれ自体をコピーする代わりに を返します。(ARCを使用していない場合は保持する必要があります)また、オブジェクトが-hashメソッドに対して常に同じ値を返すようにします。

  2. コピー可能な単純なコンテナ クラスが、元のキー オブジェクトへの強い参照を保持するようにします。コンテナはコピー可能ですが、コピー時に元のキーを渡すだけです。セマンティクスに一致するように、等価性/ハッシュ メソッドもオーバーライドします。のインスタンスだけでもNSArray、キー オブジェクトのみが含まれており、うまく機能します。

方法 1 はかなり安全に見えますが、実際には安全かどうかはわかりません。の内部動作がわからないからですNSDictionary。したがって、私は通常、Cocoa 規約で完全に安全な #2 の方法を使用します。

アップデート

現在、バージョン 6.0 以降の iOSNSHashTableにもあります。NSMapTable

于 2012-07-21T16:42:56.083 に答える