2009-04-20 9 views
19

Ich habe ein Objekt in der Ziel-c zur Laufzeit, von denen ich nur den KVC-Schlüssel kenne und ich muss den Rückgabewert Typ (zB muss ich wissen, ob es ein NSArray oder NSMutableArray) dieser Eigenschaft, wie kann ich das tun?Wie erkennt man eine Eigenschaft Rückgabetyp in Objective-C

+0

Wo die Information in deiner XML-Datei herkommen? Wäre es möglich, einen Eintrag hinzuzufügen, um den Typ jeder Eigenschaft anzugeben? –

+0

Die XML-Datei ist auch nicht von meiner Kontrolle. Ich erstelle einen XML-Serializer, der eine XML-Datei in eine Objektstruktur konvertiert. Natürlich müssen die Objekte verfügbar sein, aber ich brauche zur Laufzeit bestimmte Informationen über das Objekt, um die Daten korrekt zu füllen. – Enyra

Antwort

34

Sie sprechen über Runtime-Eigenschaft Introspektion, die zufällig ist, dass Objective-C ist very good at.

Im Fall, dass Sie beschreiben, ich nehme an, Sie eine Klasse wie dieses:

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

, die in XML so etwas wie dieses codiert wird:

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

Aus dieser Information möchten Sie um die Klasse neu zu erstellen und geben Sie ihr einen geeigneten Wert für stuff.

Hier ist, wie es aussehen könnte:

#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 

Apples Dokumentation (oben verlinkten) all die schmutzigen Details hat über das, was Sie in propertyAttrs sehen erwarten.

+2

Eigentlich wäre es gleich T @ "NSArray", &, Vstuff ;-) –

+0

Danke, du hast absolut recht. Ich habe die Änderung gemacht –

+0

Danke, das scheint der beste Weg zu sein, ich werde es versuchen. BTW. Ihr Beispiel ist ziemlich nah an dem, was ich mache, aber es kann eine beliebige XML-Datei sein, also ist mein Schlüssel der Elementname. – Enyra

1

können Sie isKindOfClass Nachricht im NSObject Protocol

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

das Problem ist, das Objekt neu erstellt wird, so ist auch der Wert der Eigenschaft null. Ich habe nur einen KVC-Schlüssel, von dem ich Ereignis nicht weiß, ob das Objekt wirklich diese Accessoren hat, aber wenn es es hat, muss ich den Typ dieses Rückgabewerts kennen, ohne das entsprechende Objekt in der Hand zu haben. – Enyra

+0

Warum nicht später Ihre logische Entscheidung treffen, wenn Sie ein Objekt haben werden? Ziel C ist mehr Laufzeitsprache als statisch. –

+0

@Enyra: das ist in Ordnung. Wenn das obige Objekt null ist, wird false zurückgegeben, selbst wenn es sich letztendlich um ein Array handelt. –

4

Der bevorzugte Weg ist definiert verwenden, um die Methoden zu verwenden.

Insbesondere um festzustellen, ob etwas eine Instanz einer Klasse oder einer Unterklasse dieser Klasse ist, verwenden Sie . Um festzustellen, ob etwas eine Instanz einer bestimmten Klasse ist, und nur diese Klasse (dh: keine Unterklasse), verwendet -isMemberOfClass:

Also, für Ihren Fall, würden Sie wollen, so etwas tun:

// 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

In Enyra Fall 'anObject' ist Null. Sieh Kommentare in meiner Antwort. –

+1

Dieser Test wird nicht funktionieren. Alle Arrays - auch unveränderliche - stammen von NSMutableArray ab. – Chuck

+2

isMemberOfClass: ist die Prüfung, die die Vererbung ignoriert. –

17

Billige Antwort: Verwenden Sie the NSObject+Properties source here.

Es implementiert die gleiche oben beschriebene Methodik.

+1

+1 für die große lib :) – Kjuly

+0

Ich mag es oft, das Rad neu zu erfinden, also werde ich wahrscheinlich so etwas tun und diese Bibliothek als Beispiel/Referenz verwenden. Ich danke dir sehr! –

2

Dies ist wirklich ein Kommentar zu einem Problem von Greg Maletic als Reaktion auf die Antwort von e.James 21APR09 angesprochen.

Vereinbart, dass Objective-C eine bessere Implementierung für diese Attribute verwenden könnte. Unten finden Sie eine Methode, die ich schnell zusammen warf Attribute eines einzelnen Objekts Eigenschaft abzurufen:

- (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; 
} 

Teil Liste von Attributschlüssel:

  • R Read-only
  • C Kopie des letzten Wert zugewiesen
  • & Referenz zum letzten Wert zugewiesen
  • N nichtatomare Eigenschaft
  • W Schwache Referenz

Liste bei Apple

+1

Anmerkung zu Slipp D. Thompsons Editierung von der Bracket-Nachricht zur Dot-Syntax: Die obige Punktsyntax-Bearbeitung führt tatsächlich zu einem Compiler-Fehler für den Aufruf "obj.class" in Xcode 6.4 und der Xcode 7 Beta (Sie würden müssen die "id" -Deklaration auf "NSObject" auflösen, um aufzulösen). Ich bin Befürworter von Jon Reids Meinung, dass die Verwendung der Punktsyntax für Messaging in ObjC generell unklug ist: http://qualitycoding.org/dot-notation/#comments – Jalakoo

0

Wenn Sie wissen, dass die Eigenschaft definiert ist:

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

Und vergleichen mit isKindOfClass, issubclass usw.

+1

Was ist, wenn der aktuelle Wert Null ist? – JBlake

Verwandte Themen