web-dev-qa-db-ja.com

NSStringインスタンスがNSArrayに含まれているかどうかを確認します

文字列の束を持つ配列があり、特定の文字列が配列に含まれているかどうかを確認したい。配列でcontainsObject:メッセージを使用すると、正しい結果が得られます。同じ文字列を持つすべてのNSStringオブジェクトは同じオブジェクトを指しますか?または、なぜcontainsObject:が機能するのですか?

NSArray *stringArray = [NSArray arrayWithObjects:@"1",@"2",@"3",anotherStringValue, nil];
if([stringArray containsObject:@"2"]){
  //DO SOMETHING
}
75
the Reverend

はい、ハードコードされたNSString(文字列リテラル)(つまり、ソースコードの@"...")は、プロセスの実行中に無期限に存在する文字列に変換されます。

ただし、NSArraycontainsObject:メソッドは、そのオブジェクトで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:の(短い)ドキュメントを読むことができます。

168
Regexident

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

17
ughoavgfhw

containsObjectを使用して、特定の文字列が存在するかどうかを確認できます。

NSArray *stringArray = [NSArray arrayWithObjects:@"1",@"2",@"3",anotherStringValue, nil];

if ( [stringArray containsObject: stringToFind] ) {
    // if found
} else {
    // if not found
}
3
isuru