13

この最近のSOの議論は私を混乱させました。のNSMutableArrayプロトタイプaddObject:

- (void)addObject:(id)anObject

idobjc.hで次のように定義されています

typedef struct objc_class *Class;
typedef struct objc_object {
    Class isa;
} *id; 

NSObjectまたはサブクラスをに追加するとNSMutableArray、その保持カウントが増加し、それを削除すると、NSMutableArray減少します。これは、またはサブクラスid typeではないがに追加された場合、メッセージを保持および解放するために応答する必要があることを意味しますか?の定義はこれを強制するようには見えません。標準のメモリ管理メッセージに応答する必要があるのはObjectiveCディレクティブですか?NSObjectNSMutableArrayidid type

4

6 に答える 6

7

ほとんどのFoundationコンテナ(および、ほとんどのApple開発クラス、およびある程度サードパーティによって開発されたほとんどのクラス)についての難しい真実は、メソッドがid型を受け入れるとき、それは実際に読み取る必要がid<NSObject>あるということです。つまり、に応答するすべての型を意味します。NSObjectプロトコル。階層の一部ではないクラスのインスタンスは、およびNSObjectに応答する可能性が低く、これは、それらをコンテナーに追加しようとするときに特に不便です。また、、、、、、およびFoundationコンテナーが何らかの理由でコンテンツに対して使用できる他のすべてのメソッドに応答する可能性はほとんどありません。-retain-release-hash-isEqual:-description-copy

たとえばClass、Foundationコンテナにオブジェクトを追加しようとすると(NSMapTableこれは多くの柔軟性を念頭に置いて設計されているため)、「最新の」ObjCクラスは、からNSObject、またはで継承することが期待されるため、壁にぶつかります。少なくともNSObjectプロトコルを実装します。

ただし、これは非常にまれな状況です。Classから継承しない、ほとんど唯一の便利なクラスですNSObject

于 2011-10-26T15:37:47.257 に答える
4

これは、NSObjectまたはサブクラスではないIDタイプがNSMutableArrayに追加された場合、メッセージの保持と解放に応答する必要があることを意味しますか?

デフォルトでは、はい。ただし、CF-APIを使用した場合の回避策があります。

idの定義はこれを強制するようには見えません。任意のIDタイプが標準のメモリ管理メッセージに応答する必要があるのはObjectiveCディレクティブですか?

それはまさにライブラリが書かれた方法です。ルートクラス(NSObjectから継承しない)は非常に珍しいものです。別の方法もありますが- (void)addObject:(id<NSObject>)、ルートクラスにかなり大きな拡張が必要になります...おそらくより良い解決策はNSReferenceCounted、から関連するビットを取得するプロトコルNSObjectでした。

ただし、NS-collectionsタイプは、実際にはNSObjectsを処理していることを前提としています(たとえば、ディクショナリはandを使用hashしますdescription)。

于 2011-10-26T15:39:42.670 に答える
2

いいえ、タイプ「id」のオブジェクトが保持/解放メッセージに応答する必要があるという規則はありません。実際、これらの種類のメソッドの存在を保証することが、NSObjectプロトコル(クラスではない)の目的であると言う人もいるかもしれません。ただし、「id」はコンパイラに「タイプチェックを行わない」ことを指示するため、これらのメソッドを実装していないnsarrayにオブジェクトを追加すると、コンパイルされますが、ランタイムがクラッシュします。詳細な説明については、 http: //unixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs-id.htmlを参照してください。

于 2011-10-26T15:37:01.353 に答える
0

非オブジェクト型をに入れてはいけません。NSArrayたとえば、の配列を格納したい場合は、CGRectsそれらをオブジェクトにラップしてNSValue格納します(これはetcでも同じですCGPoint, CGSize)。

カスタム構造体がある場合は、NSObject子孫ラッパーが必要になります。これは、そもそも目的を打ち破ります。

于 2011-10-26T15:34:17.313 に答える
0

保持/解放したくないアイテムを保持する配列が本当に必要な場合は、を使用して配列を作成しCFArrayCreateMutable、適切なコールバックを渡すことをお勧めします。(CFMutableArrayフリーダイヤルでブリッジされNSMutableArrayます。)

于 2011-10-26T16:47:47.057 に答える
0

上記の技術的な議論に加えて、答えは言語の歴史と構文よりも慣習に対するその好みに関連していると思います。正式なプロトコルは元々言語の一部ではありませんでした—すべてが非公式でした。その後、Appleは主に正式なプロトコルに移行しましたが、非公式のプロトコルは言語の一部であり、公式APIの一部で使用されています。したがって、これらは完全にサポートされている、Objective-Cのファーストクラスの部分です。

のドキュメントを見るNSArrayと、とりわけ次のように書かれています。

ほとんどの場合、カスタムNSArrayクラスはCocoaのオブジェクト所有権規則に準拠している必要があります。したがって、コレクションに追加する各オブジェクトに保持を送信し、コレクションから削除する各オブジェクトに解放する必要があります。もちろん、NSArrayをサブクラス化する理由が、標準とは異なるオブジェクト保持動作(たとえば、非保持配列)を実装するためである場合は、この要件を無視できます。

と:

NSArrayは、CoreFoundationの対応するCFArray[...]と「フリーダイヤルでブリッジ」されており、NSArrayでは簡単に実行できないことをCFArrayで実行できる場合があります。たとえば、CFArrayは一連のコールバックを提供し、その一部はカスタムの保持解放動作を実装するためのものです。これらのコールバックにNULL実装を指定すると、非保持配列を簡単に取得できます。

したがって、あなたの質問は誤った前提、具体的にはドキュメントの部分的な読み方または言語の不完全な考慮のいずれかに基づいています。

id <NSObject>NSObjectプロトコルが、で使用できるようにオブジェクトが実装する必要のあるプロトコルと一致しないため、正しく使用されていませんNSArray。代わりに、たまたまのサブセットである非公式のプロトコルがNSObjectドキュメントで確立されています(ただし、2回目の非公式の削除ではまれです)。非公式のプロトコルはますます一般的ではありませんが、それらは有効であり、まだ例外ではありません。

したがって、私の答えの短いバージョンは次のとおりです。NSArray非公式のプロトコルを文書化します。そのプロトコルはと同じではありませんNSObject。非公式のプロトコルは構文で表されないため、id

于 2011-10-27T11:15:29.677 に答える