Controlla se l’object è di tipo Classe

Ho un metodo che riceve un NSArray di oggetti Class e ho bisogno di verificare se sono tutti generati di Class con il codice seguente:

 NSMutableArray *arr = [[NSMutableArray alloc] init]; [arr addObject:[NSObject class]]; [arr addObject:[NSValue class]]; [arr addObject:[NSNumber class]]; [arr addObject:[NSPredicate class]]; [arr addObject:@"not a class object"]; 

Il problema è che Class non è una class objective-c, è una struc, quindi non posso usare solo

  for (int i; i<[arr count]; i++) { Class obj = [arr objectAtIndex:i]; if([obj isKindOfClass: [Class class]]) { //do sth } } 

Quindi, ho bisogno di controllare se la variabile obj è di tipo Class , suppongo che sarà in C direttamente, ma come posso farlo?

Sarà un vantaggio se la risposta fornisce anche un modo per verificare se l’elemento nell’array è un NSObject , come gli elementi nel codice di esempio, il NSPredicate sarebbe anche true per il controllo NSObject

Per determinare se un “object” è una class o un’istanza è necessario verificare se si tratta di una meta class in un processo a due fasi. Prima chiamata object_getClass quindi controlla se si tratta di una meta class che usa class_isMetaClass . Sarà necessario #import .

 NSObject *object = [[NSObject alloc] init]; Class class = [NSObject class]; BOOL yup = class_isMetaClass(object_getClass(class)); BOOL nope = class_isMetaClass(object_getClass(object)); 

Sia la Class che l’ *id hanno lo stesso layout di struttura ( Class isa ), pertanto possono essere posizionati come oggetti e possono entrambi ricevere messaggi, rendendo difficile determinare quale sia il significato. Questo sembra essere l’unico modo in cui sono riuscito a ottenere risultati coerenti.

MODIFICARE:

Ecco il tuo esempio originale con il controllo:

 NSMutableArray *arr = [[NSMutableArray alloc] init]; [arr addObject:[NSObject class]]; [arr addObject:[NSValue class]]; [arr addObject:[NSNumber class]]; [arr addObject:[NSPredicate class]]; [arr addObject:@"not a class object"]; for (int i; i<[arr count]; i++) { id obj = [arr objectAtIndex:i]; if(class_isMetaClass(object_getClass(obj))) { //do sth NSLog(@"Class: %@", obj); } else { NSLog(@"Instance: %@", obj); } } [arr release]; 

E l'output:

Classe: NSObject
Classe: NSValue
Classe: NSNumber
Classe: NSPredicate
Istanza: non un object di class

Aggiornamento: in iOS 8+ o OS X 10.10+, puoi semplicemente:

 object_isClass(obj) 

(Sarà necessario #import .)

La risposta di Joe è buona. Una semplice alternativa che funziona nella maggior parte delle situazioni è controllare se l’object si restituisce in risposta alla class .

 if ([obj class] == obj) { … } 

Questo funziona perché la NSObject sostituisce la class e restituisce l’object di class (stesso): consultare il Riferimento di class NSObject . Ciò non richiede le intestazioni di runtime, ma si presuppone che gli oggetti siano sottoclassi di NSObject e che non sovrascrivano -class o +class e facciano qualcosa di insolito.


Con l’input nella domanda, i risultati sono gli stessi di Joe:

 NSMutableArray *arr = [[NSMutableArray alloc] init]; [arr addObject:[NSObject class]]; [arr addObject:[NSValue class]]; [arr addObject:[NSNumber class]]; [arr addObject:[NSPredicate class]]; [arr addObject:@"not a class object"]; for (id obj in arr) { if ([obj class] == obj) { NSLog(@"Class: %@", obj); } else { NSLog(@"Instance: %@", obj); } } 

Classe: NSObject
Classe: NSValue
Classe: NSNumber
Classe: NSPredicate
Istanza: non un object di class

Se è necessario verificare se l’object nell’array è un object di Class , è ansible verificare se risponde ai metodi di class.

 for ( id obj in arr ) { if (([obj respondsToSelector:@selector(isSubclassOfClass:)]) && (obj == [NSObject class]) ) { NSLog(@"%@", obj); } } 

Una volta che sai che è un object Class verificando se risponde a isSubclassOfClass: puoi controllare l’uguaglianza diretta con [NSObject class] .

Il dettaglio sta arrivando.

Innanzitutto, in objc.h , possiamo trovare questi codici:

 /// An opaque type that represents an Objective-C class. typedef struct objc_class *Class; 

ciò significa che tutta la Objective-C class è di tipo Class , incluso NSObject .

quindi la tua domanda:

 [arr addObject:[NSObject class]]; /// YES [arr addObject:[NSValue class]]; /// YES [arr addObject:[NSNumber class]]; /// YES [arr addObject:[NSPredicate class]]; /// YES [arr addObject:@"not a class object"]; /// NO, It's just a NSString. 

Secondo, come hai detto, “La Class non è una objective-c class , è una struttura”. Voglio spiegare che tutte le objective-c class sono in realtà Struct in C.

In runtime.h , trovo questi codici, forse aiutaci:

 struct objc_class { Class isa OBJC_ISA_AVAILABILITY; #if !__OBJC2__ Class super_class OBJC2_UNAVAILABLE; const char *name OBJC2_UNAVAILABLE; long version OBJC2_UNAVAILABLE; long info OBJC2_UNAVAILABLE; long instance_size OBJC2_UNAVAILABLE; struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; struct objc_method_list **methodLists OBJC2_UNAVAILABLE; struct objc_cache *cache OBJC2_UNAVAILABLE; struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; #endif } OBJC2_UNAVAILABLE; 

Finalmente arriviamo a NSObject.h line30--32 , questi tre metodi. Possiamo sapere che aClass è di tipo Class . Ciò dimostra ulteriormente che tutta la class objective-c è di tipo Class .

 - (BOOL)isKindOfClass:(Class)aClass; - (BOOL)isMemberOfClass:(Class)aClass; - (BOOL)conformsToProtocol:(Protocol *)aProtocol; 

È quasi la prima volta che rispondo alla domanda nel mio povero inglese. Se avete anche domande, rispondete presto, farò del mio meglio per spiegarlo. E ti suggerisco anche di leggere NSObject.h , runtime.h , codice objc.h , forse ti aiuterà.

Nessun problema qui è come lo fai:

 if([NSStringFromClass([obj class]) isEqualToString:@"Class"]){ NSLog(@"It is type of Class"); } 

modificare

Oppure puoi rendere la tua Classe conforms a un protocollo: e controlla se obj che ottieni dalla matrice è conforms a questo protocollo come questo:

 if([obj conformsToProtocol:@protocol(MyClassProtocol)]) 

modificare

Oppure puoi verificare se ciò che ottieni dall’array è un componente NSObject

 if ([object conformsToProtocol:@protocol(NSObject)]) { // Do something }