2010-06-19 7 views
48

Jak przeszukiwać NSSet lub NSArray dla obiektu, który ma określoną wartość dla określonej właściwości?Jak przeszukiwać NSSet lub NSArray dla obiektu, który ma określoną wartość dla określonej właściwości?

Przykład: Posiadam NSSet z 20 obiektami, a każdy obiekt ma właściwość type. Chcę uzyskać pierwszy obiekt, który ma [theObject.type isEqualToString:@"standard"].

Pamiętam, że w jakiś sposób można było używać predykatów dla tego rodzaju rzeczy, prawda?

Odpowiedz

76
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"type == %@", @"standard"]; 
NSArray *filteredArray = [myArray filteredArrayUsingPredicate:predicate]; 
id firstFoundObject = nil; 
firstFoundObject = filteredArray.count > 0 ? filteredArray.firstObject : nil; 

NB: Pojęcie pierwszego znalezionego obiektu w NSSet nie ma sensu, gdyż kolejność obiektów w zestawie jest niezdefiniowany.

+0

Czy to działa, jeśli obiekt nie ma „typem” właściwość, ale ma inny obiekt (powiedzmy "zadanie"), a to jest "zadanie", które ma właściwość "typ"? – darksider

+0

Tak, ale klasa musi być kodowaniem klucz-wartość zgodnym z kluczami, których chcesz użyć w predykacie. –

+0

'indexOfObjectPassingTest' wydaje się być lepszy z dwóch powodów: (1) Używasz rzeczywistej metody zamiast * string * (2) Zatrzymujesz się na" pierwszym "znalezionym elemencie - nie ma znaczenia, że ​​zestaw nie jest zamówiony, wciąż możesz chcieć tylko jednego przedmiotu. –

4
NSArray* results = [theFullArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF.type LIKE[cd] %@", @"standard"]]; 
17

Możesz otrzymać filtrowaną tablicę, jak opisali Jason i Ole, ale ponieważ chcesz tylko jeden obiekt, użyłbym - indexOfObjectPassingTest: (jeśli jest w tablicy) lub -objectPassingTest: (jeśli jest w zestawie) i unikaj tworzenia druga tablica.

+1

To wydaje się dobrym pomysłem dla NSArray, ale metoda w NSSet jest w rzeczywistości '-objectsPassingTest:' (uwaga w liczbie mnogiej), więc ten pomysł nie jest bezpośrednio możliwy, jeśli rozumiem to poprawnie. – Ashley

13

Generalnie używam indexOfObjectPassingTest:, ponieważ uważam, że wygodniej jest wyrazić mój test w kodzie Objective-C niż w składni NSPredicate. Oto prosty przykład (wyobrazić, że integerValue był rzeczywiście nieruchomość):

NSArray *array = @[@0,@1,@2,@3]; 
NSUInteger indexOfTwo = [array indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { 
    return ([(NSNumber *)obj integerValue] == 2); 
}]; 
NSUInteger indexOfFour = [array indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { 
    return ([(NSNumber *)obj integerValue] == 4); 
}]; 
BOOL hasTwo = (indexOfTwo != NSNotFound); 
BOOL hasFour = (indexOfFour != NSNotFound); 
NSLog(@"hasTwo: %@ (index was %d)", hasTwo ? @"YES" : @"NO", indexOfTwo); 
NSLog(@"hasFour: %@ (index was %d)", hasFour ? @"YES" : @"NO", indexOfFour); 

Wyjście z tego kodu jest:

hasTwo: YES (index was 2) 
hasFour: NO (index was 2147483647)