Проверьте, содержится ли экземпляр NSString в NSArray
У меня есть массив с цепочкой строк, и я хочу проверить, содержится ли определенная строка в массиве. Если я использую сообщение containsObject
: в массиве, я получаю правильные результаты. Все объекты NSString
с одной и той же строкой указывают на один и тот же объект? Или почему containsObject
: работает?
NSArray *stringArray = [NSArray arrayWithObjects:@"1",@"2",@"3",anotherStringValue, nil];
if([stringArray containsObject:@"2"]){
//DO SOMETHING
}
Ответы
Ответ 1
Да, жестко закодированные NSStrings (строковые литералы) (то есть любые @"..."
в исходном коде) превращаются в строки, которые существуют бесконечно во время выполнения вашего процесса.
Однако методы NSArray containsObject:
вызывают isEqual:
на своих объектах, поэтому даже динамически созданная строка, такая как [NSString stringWithFormat:@"%d", 2]
, вернет YES
в вашем примере фрагмента.
Это связано с тем, что метод NSString isEqual:
(или, точнее, его isEqualToString:
) реализован как контент (или сравнение идентификаторов указателей) и, таким образом, возвращает 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:
, НЕ, потому что литеральные строки используют один и тот же постоянный экземпляр, НО, потому что containsObject:
по вызовам соглашений isEqual:
, о котором известно.
Возможно, вы захотите прочитать (короткую) документацию для isEqual:
из протокола NSObject.
Ответ 2
containsObject:
выполняет проверку значения, а не проверку указателя. Он использует метод isEqual:
, определенный NSObject и переопределяемый другими объектами для тестирования. Поэтому, если две строки содержат одну и ту же последовательность символов, они будут считаться одинаковыми.
Различие между тестированием указателя и тестированием ценности очень важно в некоторых случаях. Константные строки, определенные в исходном коде, объединяются компилятором, так что они являются одним и тем же объектом. Однако строки, созданные динамически, не являются одним и тем же объектом. Вот пример программы, которая продемонстрирует это:
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