KVC - Test ob key vorhanden

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • KVC - Test ob key vorhanden

    Hallo zusammen,

    Ich möchte object Properties per KVC abfüllen. Da es eine Library wird, weiss ich zur Laufzeit nicht, ob das Objekt den jeweiligen Key wirklich unterstützt. Im Moment teste ich das folgendermassen:

    Quellcode

    1. [object respondsToSelector:r:key];


    Das ssagt aber nur aus, ob das Objekt einen Get-Accessor hat, aber nicht ob es schreibbar ist und den Set-Accessor zusammenbasteln, scheint mir etwas zu heiss. Gibt es da eine bessere Methode um zu schauen, ob ein Objekt den Key unterstützt?

    Grüsse Diskordia
    Ialea iacta est
  • Weiß nicht, ob man das bei Objective-C so sehen kann. Aber davon abgesehen ist der Test auf den Setter nicht heiß. Die Naming-Conventions sind einzuhalten, sonst gibt es ohnehin Ärger. Der Test auf eine Exception hat zudem den Vorteil, dass der gesamte KVC-Algorithmus abgearbeitet wird, der sich übrigens schon einmal geändert hat (.2 -> .3 IIRC)

    Im Laufzeitsystem kannst du zudem auf die Property testen. Aber ich sehe darin keinen Sinn.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Ich habe gleich nochmals ein ähnliches Problem. Die Ausgangslage ist die gleiche, ich habe ein object und ein KVC Key, von dem ich nicht weiss ob ein Accessor vorhanden ist.
    Und nun möchte ich herausfinden ob der return value type ein NSArray ist. Das Problem ist, der return value kann nil sein ansonsten könnte ich es ja per isKindOfClass: herausfinden.
    Einfach nur ein array zuweisen und sehen was passiert kann ich auch nicht, denn wenn der return value nicht nil ist, möchte ich die vorhandene instanz nicht wegwerfen.
    Ialea iacta est
  • Ich habe mir mal folgendes zusammengestiefelt, hat jemand ne bessere Idee?

    Quellcode

    1. - (BOOL)valueForKeyIsArray:(NSString *)key fromTarget:(id)
    2. {
    3. @try {
    4. NSString *lowerCaseKey = [[[key substringToIndex:1] lowercaseString] stringByAppendingString:[key substringFromIndex:1]];
    5. id propertyValue = [target valueForKey:lowerCaseKey];
    6. // return yes if the return value is not nil and if it's a mutable array
    7. if(propertyValue && [propertyValue isKindOfClass: [NSMutableArray class]]) {
    8. return YES;
    9. }
    10. // return yes if the return value is nil and a mutable array can be assigned
    11. else if(!propertyValue) {
    12. NSMutableArray *newArray = [NSMutableArray array];
    13. [target setValue:newArray forKey:lowerCaseKey];
    14. return YES;
    15. }
    16. return NO;
    17. }
    18. @catch (NSException * e) {
    19. // return no, if the property does not exist, or if the new mutable array can not be assigned
    20. return NO;
    21. }
    22. }
    Alles anzeigen
    Ialea iacta est
  • Man kann es ein bisschen umdrehen und spart dann ein paar Buchstaben. Ob da der Compiler jetzt großartig anderen Code erzeugt, weiß ich nicht.

    Quellcode

    1. - (BOOL)valueForKeyIsArray:(NSString *)key fromTarget:(id)
    2. {
    3. @try {
    4. NSString *lowerCaseKey = [[[key substringToIndex:1] lowercaseString] stringByAppendingString:[key substringFromIndex:1]];
    5. id propertyValue = [target valueForKey:lowerCaseKey];
    6. // return yes if the return value is nil and a mutable array can be assigned
    7. if(!propertyValue) {
    8. NSMutableArray *newArray = [NSMutableArray array];
    9. [target setValue:newArray forKey:lowerCaseKey];
    10. return YES;
    11. }
    12. // return yes if the return value is not nil and if it's a mutable array
    13. if([propertyValue isKindOfClass: [NSMutableArray class]]) {
    14. return YES;
    15. }
    16. return NO;
    17. }
    18. @catch (NSException * e) {
    19. // return no, if the property does not exist, or if the new mutable array can not be assigned
    20. return NO;
    21. }
    22. }
    Alles anzeigen
    Michael
  • Ich verstehe dein Problem nicht ganz:

    a) Du kannst -isKindOfClass aus nil anwenden, weil BOOL ein integraler Typ ist – auf allen CPUs.

    b) Du kannst es auch an ein Array zuweisen. Ich weiß nicht, was du mit wegschmeißen meinst!? Du hast nicht die Ownership für eine Returnwert. Im Übrigen darf man auch -retain und -release an nil senden, was auch ständig geschieht.

    c) Ansonsten verstehe ich schon die die gesamte Zeit nicht, warum du das überhaupt wissen willst. Du bekommst einen Key. Der muss stimmen. Ansonsten kümmert sich schon jemand ganz anderes um die Exception.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Original von Amin Negm-Awad
    Ich verstehe dein Problem nicht ganz:

    a) Du kannst -isKindOfClass aus nil anwenden, weil BOOL ein integraler Typ ist – auf allen CPUs.

    b) Du kannst es auch an ein Array zuweisen. Ich weiß nicht, was du mit wegschmeißen meinst!? Du hast nicht die Ownership für eine Returnwert. Im Übrigen darf man auch -retain und -release an nil senden, was auch ständig geschieht.

    c) Ansonsten verstehe ich schon die die gesamte Zeit nicht, warum du das überhaupt wissen willst. Du bekommst einen Key. Der muss stimmen. Ansonsten kümmert sich schon jemand ganz anderes um die Exception.

    Ich baue mir einen XmlSerializer, im Prinzip etwas ähnliches was der NSArchiver/NSUnarchiver macht, nur funktioniert das ganze mit einem beliebigen xml file ... solange eine entsprechende Klassenstruktur vorhanden ist.
    Wenn ein xml file ohne zusätzliche Information / Konfiguration deserialisiert wird ist nicht bekannt, welche Klassen, resp. Accessoren vorhanden sind.
    Lese ich den root node vom xml, nehme ich erst mal den node name und versuche die entsprechende Klasse zu finden und zu instanzieren. Danach werden Attributte und Elemente gelesen, evtl. weitere Klassen gesuch, instanziert und abgefüllt. Das funktioniert soweit ganz gut, sind jedoch mehrere gleiche Elemente vorhanden, oder ein Element für das keine Klasse gefunden wird, welches jedoch mehrere gleiche Elemente hat, muss das in eine Liste, resp. Array. Das ganze funktioniert natürlich per Element Name, welcher ich gleich als KVC Key verwende.
    D.h. wenn ich ein Kind-Element lese, möchte ich erst mal schauen, ob ein entsprechendes Property mit Array Type existiert, wonach ich nachher das Element handhaben kann.
    Ganz ähnliche Probleme werde ich später wohl auch beim kreieren des xml Trees bekommen, aber one by one ^^

    zu a)
    Wenn ich folgendes mache und propertyValue ist nil:

    Quellcode

    1. id propertyValue = [target valueForKey:lowerCaseKey];
    2. BOOL result = [propertyValue isKindOfClass:[NSArray class]];

    Gibt mir -isKindOfClass doch in jedem Fall NO zurück?

    zu b)
    Ich kann ja dem Property einfach per KVC ein neuer Array zuweisen und die Exception abfangen wenn es nicht geht, falls die Klasse den Property Array jedoch schon selbst instanziert, release ich diese bei einer Neuzuweisung, da eine ich mit "wegschmeissen" ^^

    zu c)
    Wie oben beschrieben lese ich den Key vom xml file und versuche die Objektstruktur zu erstellen, ohne wirklich zu wissen, ob die Klassen, resp. Keys vorhanden sind. Später soll das auch konfigurierbar sein, aber es soll halt auch ohne funktionieren.

    Naja ist das erste Mal, dass ich sowas in Objective-c mache und sind leider nicht ganz die Standard-Konstrukte, welche man üblicherweise braucht, deshalb bin ich da etwas am Anschlag ^^
    Ialea iacta est
  • Original von Amin Negm-Awad
    Ich kann dir nicht mehr folgen. Bist du mal in Köln?


    Mh leider eher selten :( <---- Schweizer ^^
    Aber ich lade mal meine Sourcen hoch, vielleicht kannst du mir danach folgen ^^ Hab leider nur noch diese Woche Zeit um daran was zu machen, nachher bin ich leider im grünen Dienst.
    Ialea iacta est
  • Ich habs jetzt so gemacht, funktioniert ganz gut:

    Quellcode

    1. - (BOOL)valueForKeyIsArray:(NSString *)key fromTagret:(id)target
    2. {
    3. NSString *lowerCaseKey = [self convertToKVCKey:key];
    4. objc_property_t property = class_getProperty([target class], [lowerCaseKey UTF8String]);
    5. //const char *propertyAttrs = property_getAttributes(property);
    6. NSString *propertyAttrs = [NSString stringWithUTF8String:property_getAttributes(property)];
    7. //NSString *encodedType = [NSString stringWithUTF8String:@encode(NSArray *)];
    8. NSString *encodedType = @"@\"NSArray\"";
    9. NSRange range = [propertyAttrs rangeOfString:encodedType options:NSLiteralSearch];
    10. return range.location != NSNotFound;
    11. }
    Alles anzeigen


    Grüsse Diskordia
    Ialea iacta est