2010-11-22 24 views
3

Je travaille en Objective-C sur l'iPhone et ont besoin de savoir si un inherits « classe » de « NSObject ».Comment savoir si une classe hérite de NSObject (Objective-C)

J'ai essayé de vérifier si elle répond à un sélecteur NSObject:

bool success = [myClass respondsToSelector:@selector(class)]; 

mais vous pouvez deviner ce qui est arrivé ... il n'a même pas répondu à « respondsToSelector: » il lance un « ne met pas en œuvre doesNotRecognizeSelector: "exception.

J'ai essayé d'attraper cette exception, mais il semble que ce ne peut pas être pris avec un @ répar- @ prise.

Des idées?

+2

Je pense que la meilleure question est de savoir comment vous êtes à traiter avec ces classes qui ne sont pas hérite de NSObject. Il ne devrait pas y en avoir sauf Protocole. – Chuck

+1

@Chuck et 'NSProxy'. –

+0

Vous voulez dire '@selector (class)'. Je ne pense pas qu'il y ait quoi que ce soit dans le SDK qui réponde '' + class: '. –

Répondre

7

Aller directement à l'exécution Objective-C:

#import <objc/runtime.h> 

/* originally posted version — works because eventually class_getSuperclass(class) 
returns nil, and class_getSuperclass(nil) does so also. */ 
BOOL classDescendsFromClass(Class classA, Class classB) 
{ 
    while(1) 
    { 
     if(classA == classB) return YES; 
     id superClass = class_getSuperclass(classA); 
     if(classA == superClass) return (superClass == classB); 
     classA = superClass; 
    } 
} 

/* shorter version; exits straight after classA turns into nil */ 
BOOL classDescendsFromClassShorter(Class classA, Class classB) 
{ 
    while(classA) 
    { 
     if(classA == classB) return YES; 
     classA = class_getSuperclass(classA); 
    } 

    return NO; 
} 
... 

if(classDescendsFromClass(classToTest->isa, [NSObject class]) ... 

class_getSuperclass fait ce qu'il dit, et il est sûr de comparer métaclasses par pointeur dans l'exécution Objective-C, car il est seulement exactement une instance de la métaclasse pour chaque classe. Le pointeur isa est la seule chose qui soit définitivement dans la structure objc_object.

EDIT: En outre, il y a des bugs connus dans le simulateur iPhone qui causent quelques exceptions de ne pas être pris par des blocs try/catch. Je les ai signalés comme un bug à Apple et on m'a dit que le mien était un doublon, donc ils sont certainement au courant. Avez-vous essayé votre code sur un vrai appareil ou juste dans le simulateur?

EDIT2: du contexte plus large donné ailleurs dans cette conversation, quelque chose comme cela pourrait être plus intelligent:

#import <objc/runtime.h> 

BOOL classRespondsToSelector(Class classA, SEL selector) 
{ 
    return class_getInstanceMethod(classA, selector) ? YES : NO; 
} 

.... 
if(classRespondsToSelector(instance->isa, @selector(respondsToSelector:)) 
{ 
    // great, we've got something that responds to respondsToSelector:; do the 
    // rest of our querying through there 
} 
+0

Cette réponse est excellente et fonctionne parfaitement. Vous avez raison sur les blocs try/catch du simulateur/appareil. J'ai lu que les blocs try/catch ne devraient pas être utilisés pour contrôler le flux (en obj-c), et je ne suis pas prêt à perdre le débogage du simulateur, donc je m'en tiendrai au concept 'getSuperclass'. – bendytree

+0

Ce n'est pas tout à fait vrai; Je me suis permis de devenir un peu confus - le pointeur isa de NSObject pointe vers NSObject (ie, même la métaclasse NSObject est elle-même une sous-classe de NSObject), mais NSObject n'est pas une super-classe de lui-même. Donc, si (classA == superClass) termine classDescendsFromClass une itération plus tard que nécessaire (parce qu'elle finit par devenir nulle comme une superclasse de zéro). Je vais corriger le code. – Tommy

+1

Si vous préférez plus de syntaxe Obj-C: https://gist.github.com/BillinghamJ/6709374 –

4

Vous pouvez utiliser les méthodes isKindOfClass: et isMemberOfClass: pour déterminer si une classe est une sous-classe d'une autre classe ou s'il s'agit d'une classe particulière.

+4

Ces méthodes font partie du protocole NSObject. Les objets qui ne sont pas conformes au protocole NSObject peuvent ne pas répondre à ces messages. – Greg

+0

Vrai, mais comme tout le monde le dit, pourquoi traiteriez-vous des objets qui ne sont pas conformes au protocole NSObject? C'est une question plus vaste et beaucoup plus importante. Il ne devrait pas y avoir de raison pour que vous n'ayez pas un objet qui ne soit pas conforme à ce protocole. – Jasarien

+1

Que faire si vous examinez un objet Class? –

1

respondsToSelector: lui-même est un sélecteur défini NSObject, donc vous ne pouvez pas l'utiliser. Je ne crois pas qu'il y ait un moyen de le faire sans aller très loin dans les internes d'Objective-C. Puis-je demander pourquoi vous avez des objets qui ne sont pas des descendants de NSObject? Apple vous recommande fortement de ne pas essayer de les créer, et avec raison.

+2

En fait, NSProxy est une classe qu'Apple fournit qui n'hérite pas de NSObject. Il est cependant conforme au protocole NSObject qui est plus important. – cobbal

+0

Il est raisonnablement prudent de supposer que tout va répondre à tout ce qui est défini dans NSObject. NSProxy ne le fait pas, mais devrait transmettre à de "vrais" objets qui le font. –

-3

La classe 'Class' n'hérite pas de NSObject. Cela signifie que les méthodes définies par NSObject (telles que isKindOfClass ou respondsToSelector) ne peuvent pas être utilisées.

Qu'essayez-vous de faire avec cela en premier lieu?

+0

-1 c'est le cas. Une 'Class' est une instance de la métaclasse, par ex. -NSObject est une instance de + NSObject dont la super-classe est -NSObject, par conséquent -NSObject est une instance de -NSObject. Je ne suis pas sûr que les métaclasses sont des instances (probablement aussi NSObject!), Ou que se passe-t-il si vous utilisez une autre classe racine (ie si vous n'héritez pas de NSObject), mais que les métaclasses sont la base des méthodes de classe aux méthodes statiques, qui n'ont pas de "soi"). –

+1

-1 il n'y a pas de classe 'Class' – user102008