変数が NSArray か NSMutableArray かを確認するにはどうすればよいですか?
8 に答える
*この回答が書かれてから NS{,Mutable}Array の実装が変更されたことに注意してください。その結果、isKindOfClass:
動作するようになりました。どのプラットフォームで、いつ、どこで、わかりません。
安全であることが文書化されるまでは、コレクションが可変か不変かを検出しようとするコードを書かないことを強くお勧めします。安全であったとしても、そのような設計パターンはほとんどの場合、重大な設計上の欠陥を示しています。
(アクセスできる人向け) ファイル rdar://10355515 で説明を求めます。
検討:
int main (int argc, const char * argv[]) {
NSArray *array = [NSArray arrayWithObjects: [NSObject new], nil];
NSMutableArray *mutableArray = [NSMutableArray arrayWithObjects: [NSObject new], nil];
NSLog(@"array's class: %@", NSStringFromClass([array class]));
NSLog(@"mutableArray's class: %@", NSStringFromClass([mutableArray class]));
NSLog(@"array responds to addObject: %@",
[array respondsToSelector: @selector(addObject:)] ? @"YES" : @"NO");
return 0;
}
(私が空でない配列を使用しているのNSArray
は、Cocoa が最適化として単一の共有インスタンスを提供するほど空が一般的だからです。)
array's class: NSCFArray
mutableArray's class: NSCFArray
array responds to addObject: YES
つまり、-isKindOfClass:
の実装もチェックも機能しませんaddObject:
。
つまり、NSArray と NSMutableArray の違いを見分けることはできません。これは仕様によるものであり、まさに意図された動作です。NSString
、 、NSDictionary
およびにも当てはまりますNSSet
(これらはすべて変更可能なサブクラスを持ちます)。
それは意外かもしれません。ただし、現実には、可変性をチェックする必要がある設計パターンは、使用がわかりにくく、かなりのオーバーヘッドが発生します。
たとえば、可変性のテストが一般的なパターンである場合、NSArray
インスタンスを返す Cocoa のすべてのメソッドは、実際にはNSArray
インスタンスを返す必要があり、使用されている可能性のある内部への参照を決して返さNSMutableArray
ないようにする必要があります。
悪いが技術的に正確なアドバイス...
これを行う唯一の方法は、 /ブロック[unknownArray addObject:someObject]
内で呼び出し、不変の場合にスローされる をキャッチすることです(実際の例外は、実装されていないメソッドまたはクラスが不変の例外である可能性があります)。@try
@catch
NSInternalInconsistencyException
unknownArray
いいアドバイス...
ただし、簡単な答えは、不変オブジェクトの内部を覗き込んで、内部で変更可能かどうかを確認しようとしないことです。
不変オブジェクトの可変性でのピアリングが防止される理由は、次のように機能するクラスのメソッドをサポートするためです。
- (NSArray *)internalObjects
{
return myInternalObjects;
}
オブジェクトmyInternalObjects
は可変である可能性がありますが、このクラスのこのメソッドは、「私が返すものを変更しないでください」と言っています。そうすることで重大な危険が生じる可能性があります。クラスで配列を変更できる場合は、別のアクセサーまたはミューテーター メソッドがあります。
myInternalObjects 変数への変更可能なアクセスが必要なフレンド クラスがある場合は、次のようなメソッドでフレンド クラスのみがインポートする特別なアダプター カテゴリを宣言します。
- (NSMutableArray *)mutableInternalObjectsArray;
これにより、友人 (特別なルールに違反しないほど賢いと想定している) は、必要なアクセス権を持つことができますが、より広い意味での可変性を公開することはありません。
私は次のことをします-
if([unkownArray isKindOfClass:[NSMutableArray class]]){
// This is a nsmutable array
}
else if ([unkownArray isKindOfClass:[NSArray class]]){
// This is a nsarray
}
可変配列が必要な場合は、自分で作成してください。
NSArray *someArray = /* obtain from somewhere, could be mutable, could be immutable */
NSMutableArray *mutableVersion = [someArray mutableCopy]; // definitely mutable
// later
[mutableVersion release];
内部型をチェックすることが良い考えであるケースはほとんどありません(他の回答はすでにそれらをカバーしています)。変更可能な配列が必要な場合は、既存の配列が変更可能かどうかを確認しないでください。変更可能であることがわかるように、独自の配列を作成してください。
使用する ...
[配列 isKindOfClass:[NSMutableArray クラス]]
[配列 isKindOfClass:[NSArray クラス]]
これはうまくいきます。
NSObjectの-class
メソッドを参照してください。
NSLog(@"myUnknownArray is of type: %@", [myUnknownArray class]);
+class
次の方法を使用して、より直接確認することもできます。
BOOL isMutableArray = [myUnknownArray isKindOfClass:[NSMutableArray class]];
以下を使用する必要があります。
[yourArray isKindOf: [NSArray class]]
配列はおそらく NSArray ではなく、他の低レベルの型であるため、クラスの単純な比較が失敗する可能性があるためです。配列が必要なメソッドに応答するかどうかを確認することもできます。
[yourArray respondsToSelector: @selector(addObject:)]