2010-03-31 9 views
23

Esiste un modo per costruire un predicato da filtrare in base al tipo di classe?È possibile filtrare un NSArray per classe?

Attualmente eseguo il loop della matrice e controllo la classe di ciascun oggetto. Forse c'è un modo più pulito?

+0

Perché stai mettendo oggetti così diversi nello stesso array in primo luogo? –

+12

Una ragione è se si dispone di una matrice di classi astratte. Puoi avere tutti i corsi Person, ma vuoi filtrare Medici o Avvocati. – rob5408

risposta

22

Si potrebbe aggiungere una categoria per NSObject che aggiunge un metodo "cf_className", in questo modo:

@interface NSObject (CFAdditions) 
- (NSString *) cf_className; 
@end 

@implementation NSObject (CFAdditions) 
- (NSString *) cf_className { 
    return NSStringFromClass([self class]); 
} 
@end 

Da lì, è possibile utilizzare i predicati come:

NSPredicate * p = [NSPredicate predicateWithFormat:@"cf_className = %@", aClass]; 
NSArray * filtered = [anArray filteredArrayUsingPredicate:p]; 

Se siete su il Mac, puoi semplicemente usare -[NSObject className] invece di dover creare la categoria. L'iPhone non ha quel metodo, quindi la necessità di una categoria.

+8

Puoi anche fare self.class.description –

+0

@BrianKing punto eccellente –

70

È possibile confrontare direttamente le classi anche nel predicato.

Ma probabilmente non funzionerà come ci si aspetterebbe se si cerchi di filtrare per oggetti appartenenti a cluster di classi o se si dispone di sottoclassi.

Per esempio, NSDate quando un'istanza è di solito un __NSCFDate e NSString può essere NSCFString così come altre classi private specifiche.

Probabilmente è meglio semplicemente eseguire il loop del set e utilizzare -isKindOfClass: come test.

SE si davvero desidera utilizzare NSPredicate anche se si può fare questo. Ad esempio, questo filtra una matrice per tutti gli oggetti derivati ​​da NSString. Se si desidera un abbonamento di classe rigoroso, è possibile sostituire isKindOfClass: con isMemberOfClass:.

Qualsiasi selettore che implementa tutti gli oggetti nella raccolta, accetta un argomento e restituisce un BOOL dovrebbe funzionare.

NSArray *mixedArray = {...}; 
NSPredicate *predicate = [NSPredicate predicateWithFormat: 
             @"self isKindOfClass: %@", 
             [NSString class]]; 

NSLog(@"%@", [mixedArray filteredArrayUsingPredicate:predicate]); 
+1

+1 Non ho mai pensato di mettere il selettore direttamente nel predicato. Neat! –

+1

Non è menzionato nella Predicate Programming Guide (il che significa che fare questo in una stringa di formato è tecnicamente non documentato), ma la funzione di selezione personalizzata è supportata dal riferimento: http://developer.apple.com/mac/library/ documentazione/Cacao/Riferimento/Fondazione/Classi/NSComparisonPredicate_Class/Riferimento/NSComparisonPredicate.html # // apple_ref/occ/clm/NSComparisonPredicate/predicateWithLeftExpression: rightEspressione: customSelector: molto interessante. –

+0

Sì, originariamente avevo scritto la lunga strada ma su un allodole l'ho provato nella stringa di formato e sono rimasto sorpreso nel vederlo funzionare. –

22

partire in iOS 4 e Mac OS 10.6, si può usare +[NSPredicate predicateWithBlock:] pure. Per esempio:

NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *bindings) { 
    return [object isKindOfClass:[NSString class]]; 
}]; 

questo ti permette di esprimere i propri predicati puramente in Objective-C, piuttosto che la sintassi predicato richiesto dalla predicateWithFormat:.

+4

questo merita più voti –

Problemi correlati