文字列の束を持つ配列があり、特定の文字列が配列に含まれているかどうかを確認したい。配列でcontainsObject
:メッセージを使用すると、正しい結果が得られます。同じ文字列を持つすべてのNSString
オブジェクトは同じオブジェクトを指しますか?または、なぜcontainsObject
:が機能するのですか?
NSArray *stringArray = [NSArray arrayWithObjects:@"1",@"2",@"3",anotherStringValue, nil];
if([stringArray containsObject:@"2"]){
//DO SOMETHING
}
はい、ハードコードされたNSString(文字列リテラル)(つまり、ソースコードの@"..."
)は、プロセスの実行中に無期限に存在する文字列に変換されます。
ただし、NSArrayのcontainsObject:
メソッドは、そのオブジェクトでisEqual:
を呼び出すため、動的に作成された文字列でも[NSString stringWithFormat:@"%d", 2]
などサンプルスニペットでYES
を返します。
これは、NSStringのisEqual:
(またはより正確にはisEqualToString:
)メソッドがコンテンツ認識(vs.ポインターIDの比較)に実装され、したがってYES
作成方法や時期に関係なく、まったく同じ文字シーケンスを含む文字列のペア(比較時)について。
等しい(ポインター)同一性を確認するには、配列を列挙して比較する必要があります
NSString *yourString = @"foo";
BOOL identicalStringFound = NO;
for (NSString *someString in stringArray) {
if (someString == yourString) {
identicalStringFound = YES;
break;
}
}
(ただし、これはおそらく望まないでしょう)。
またはより便利な方法で:
BOOL identicalStringFound = [stringArray indexOfObjectIdenticalTo:someString] != NSNotFound;
(おそらくこれも望まないでしょう)。
まとめ:
したがって、containsObject:
から肯定的な応答を受け取っている理由は[〜#〜] not [〜#〜]です。これは、リテラル文字列が同じ定数インスタンスを共有しているためです[〜 #〜] but [〜#〜]慣例により、containsObject:
はisEqual:
を呼び出します。これはコンテンツに対応しています。
NSObject protocol からisEqual:
の(短い)ドキュメントを読むことができます。
containsObject:
は、ポインターチェックではなく値チェックを実行します。 NSObjectによって定義され、テストのために他のオブジェクトによってオーバーライドされたisEqual:
メソッドを使用します。したがって、2つの文字列に同じ文字シーケンスが含まれている場合、それらは同じと見なされます。
ポインターテストと値テストの区別は、場合によっては非常に重要です。ソースコードで定義された定数文字列は、同じオブジェクトになるようにコンパイラによって結合されます。ただし、動的に作成された文字列は同じオブジェクトではありません。これを実証するサンプルプログラムを次に示します。
int main(int argc, char **argv) {
NSAutoreleasePool *p = [NSAutoreleasePool new];
NSString *constantString = @"1";
NSString *constantString2 = @"1";
NSString *dynamicString = [NSString stringWithFormat:@"%i",1];
NSArray *theArray = [NSArray arrayWithObject:constantString];
if(constantString == constantString2) NSLog(@"constantString == constantString2");
else NSLog(@"constantString != constantString2");
if(constantString == dynamicString) NSLog(@"constantString == dynamicString");
else NSLog(@"constantString != dynamicString");
if([constantString isEqual:dynamicString]) NSLog(@"[constantString isEqual:dynamicString] == YES");
else NSLog(@"[constantString isEqual:dynamicString] == NO");
NSLog(@"theArray contains:\n\tconstantString: %i\n\tconstantString2: %i\n\tdynamicString: %i",
[theArray containsObject:constantString],
[theArray containsObject:constantString2],
[theArray containsObject:dynamicString]);
}
このプログラムの出力は次のとおりです。
2011-04-27 17:10:54.686 a.out [41699:903] constantString == constantString2
2011-04-27 17:10:54.705 a.out [41699:903] constantString!= dynamicString
2011-04-27 17:10:54.706 a.out [41699:903] [constantString isEqual:dynamicString] == YES
2011-04-27 17:10:54.706 a.out [41699:903] theArrayの内容:
constantString:1
constantString2:1
dynamicString:1
containsObject
を使用して、特定の文字列が存在するかどうかを確認できます。
NSArray *stringArray = [NSArray arrayWithObjects:@"1",@"2",@"3",anotherStringValue, nil];
if ( [stringArray containsObject: stringToFind] ) {
// if found
} else {
// if not found
}