2009-04-20 5 views
19

J'ai un objet dans obj-c à l'exécution, dont je ne connais que la clé KVC et j'ai besoin de détecter le type de valeur de retour (par exemple, j'ai besoin de savoir si un NSArray ou NSMutableArray) de cette propriété, comment puis-je faire cela?Comment détecter un type de retour de propriété dans Objective-C

+0

D'où vient l'information vient de votre fichier XML? Serait-il possible d'ajouter une entrée pour indiquer le type de chaque propriété? –

+0

Le fichier xml est également hors de mon contrôle. Je crée un sérialiseur xml qui convertit un fichier xml dans une structure d'objet. Bien sûr, les objets doivent être disponibles, mais j'ai besoin d'informations sur l'objet lors de l'exécution pour remplir correctement les données. – Enyra

Répondre

34

Vous parlez de l'introspection des propriétés d'exécution, qui se trouve être quelque chose que Objective-C est very good at.

Dans le cas que vous décrivez, je suppose que vous avez une classe comme ceci:

@interface MyClass 
{ 
    NSArray * stuff; 
} 
@property (retain) NSArray * stuff; 
@end 

Ce qui est encodée dans quelque chose XML comme ceci:

<class> 
    <name>MyClass</name> 
    <key>stuff</key> 
</class> 

De cette information, vous voulez pour recréer la classe et lui donner également une valeur appropriée pour stuff.

Voici comment il pourrait ressembler:

#import <objc/runtime.h> 

// ... 

Class objectClass;  // read from XML (equal to MyClass) 
NSString * accessorKey; // read from XML (equals @"stuff") 

objc_property_t theProperty = 
    class_getProperty(objectClass, accessorKey.UTF8String); 

const char * propertyAttrs = property_getAttributes(theProperty); 
// at this point, propertyAttrs is equal to: [email protected]"NSArray",&,Vstuff 
// thanks to Jason Coco for providing the correct string 

// ... code to assign the property based on this information 

documentation d'Apple (lien ci-dessus) a tous les détails sales sur ce que vous pouvez vous attendre à voir dans propertyAttrs.

+2

En fait, il serait égal à T @ "NSArray", &, Vstuff ;-) –

+0

Merci, vous avez absolument raison. J'ai fait le changement –

+0

Merci, cela semble être le meilleur moyen, je vais l'essayer. Btw. votre exemple est assez proche de ce que je fais, mais il peut s'agir de n'importe quel fichier xml, donc ma clé est le nom de l'élément. – Enyra

1

Vous pouvez utiliser un message isKindOfClass

if([something isKindOfClass:NSArray.class]) 
    [somethingElse action]; 
+1

le problème est, l'objet est nouvellement créé, de sorte que la valeur de la propriété est nulle. J'ai juste une clé KVC, dont je ne sais pas si l'objet a vraiment cet accesseur, mais s'il l'a, j'ai besoin de connaître le type de cette valeur de retour sans avoir l'objet en question. – Enyra

+0

Pourquoi ne pas prendre votre décision logique plus tard quand vous aurez un objet? L'objectif C est plus le langage d'exécution que statique. –

+0

@Enyra: c'est bon. En utilisant ce qui précède, si l'objet est nul, il retournera false même s'il finit par être un tableau. –

4

Le meilleur moyen est d'utiliser les méthodes définies dans le NSObject Protocol. Plus précisément, pour déterminer si quelque chose est une instance d'une classe ou d'une sous-classe de cette classe, vous devez utiliser -isKindOfClass:. Pour déterminer si quelque chose est une instance d'une classe particulière, et que cette classe (c.-à-: non une sous-classe), utilisez -isMemberOfClass:

Alors, pour votre cas, vous voulez faire quelque chose comme ceci:

// Using -isKindOfClass since NSMutableArray subclasses should probably 
// be handled by the NSMutableArray code, not the NSArray code 
if ([anObject isKindOfClass:NSMutableArray.class]) { 
    // Stuff for NSMutableArray here 
} else if ([anObject isKindOfClass:NSArray.class]) { 
    // Stuff for NSArray here 

    // If you know for certain that anObject can only be 
    // an NSArray or NSMutableArray, you could of course 
    // just make this an else statement. 
} 
+2

Dans le cas Enyra 'anObject' est nul. Regardez les commentaires dans ma réponse. –

+1

Ce test ne fonctionnera pas. Tous les tableaux, même immuables, sont issus de NSMutableArray. – Chuck

+2

isMemberOfClass: est la vérification qui ignore l'héritage. –

17

Bonne réponse: utilisez the NSObject+Properties source here.

Il met en œuvre la même méthodologie décrite ci-dessus.

+1

+1 pour la bonne lib :) – Kjuly

+0

J'aime souvent réinventer la roue, donc je vais probablement faire quelque chose comme ça et utiliser cette bibliothèque comme exemple/référence. Merci beaucoup! –

2

Ceci est vraiment un commentaire adressant un problème soulevé par Greg Maletic en réponse à la réponse fournie par e.James 21APR09. Convenu qu'Objective-C pourrait utiliser une meilleure implémentation pour obtenir ces attributs. Voici une méthode que je rapidement jeté ensemble pour récupérer les attributs d'une propriété unique objet:

- (NSArray*) attributesOfProp:(NSString*)propName ofObj:(id)obj{ 

    objc_property_t prop = class_getProperty(obj.class, propName.UTF8String); 
    if (!prop) { 
     // doesn't exist for object 
     return nil; 
    } 
    const char * propAttr = property_getAttributes(prop); 
    NSString *propString = [NSString stringWithUTF8String:propAttr]; 
    NSArray *attrArray = [propString componentsSeparatedByString:@","]; 
    return attrArray; 
} 

Liste partielle des clés d'attributs:

  • R Lecture seule
  • C Copie de la dernière valeur affectée
  • & référence à la dernière valeur attribuée
  • N nonatomic propriété
  • W référence faible

la liste complète, Apple

+1

Note concernant l'édition de Slipp D. Thompson de la messagerie entre parenthèses à la syntaxe à points: La modification de la syntaxe à points ci-dessus entraînera une erreur de compilation pour l'appel "obj.class" dans Xcode 6.4 et Xcode 7 Beta besoin de mettre à jour la déclaration "id" à "NSObject" pour résoudre). Je suis partisan de l'opinion de Jon Reid selon laquelle l'utilisation de la syntaxe point pour la messagerie dans ObjC est généralement imprudente: http://qualitycoding.org/dot-notation/#comments – Jalakoo

0

Si vous savez que la propriété est définie:

 id vfk = [object valueForKey:propertyName]; 
     Class vfkClass = vfk.class; 

Et comparez avec isKindOfClass, issubclass, etc.

+1

Que faire si la valeur actuelle est nulle? – JBlake

Questions connexes