2013-02-19 15 views
9

Wer hat eine Idee, wie verschachtelte JSON auf NSObject-Klasse zu serialisieren? Es gibt eine Diskussion, um einfach JSON here zu serialisieren, aber es ist nicht generisch genug, um komplexe geschachtelte JSON zu bedienen.iOS: Serialisieren/Deserialisieren komplexer JSON generisch von NSObject-Klasse

Stellen Sie sich das Ergebnis von JSON ist:

{ "accounting" : [{ "firstName" : "John", 
        "lastName" : "Doe", 
        "age"  : 23 }, 

        { "firstName" : "Mary", 
        "lastName" : "Smith", 
        "age"  : 32 } 
           ],        
    "sales"  : [{ "firstName" : "Sally", 
        "lastName" : "Green", 
        "age"  : 27 }, 

        { "firstName" : "Jim", 
        "lastName" : "Galley", 
        "age"  : 41 } 
        ]} 

Von dieser Klasse:

@interface Person : NSObject{} 
@property (nonatomic, strong) NSString *firstName; 
@property (nonatomic, strong) NSString *lastName; 
@property (nonatomic, strong) NSNumber *age; 
@end 

@interface Department : NSObject{} 
@property (nonatomic, strong) NSMutableArray *accounting; //contain Person class 
@property (nonatomic, strong) NSMutableArray *sales; //contain Person class 
@end 

Wie sie allgemein auf Klasse basiert serialisiert/deserialisieren?

EDIT

Derzeit bin ich in der Lage Nutzlast wie dies für jede Klasse zu generieren:

NSMutableDictionary *Payload = [self serialize:objClass]; 

Aber es funktioniert nicht verschachtelten komplexen JSON gerecht zu werden. Hat jemand eine bessere Lösung dafür? This library für C# cater serialize/deserialze basierend auf Objektklasse. Ich möchte etwas das gleiche reproduzieren basierend auf NSObject

+0

Ein Weg, um es zu tun ist nicht - einfach weitermachen und mit NSDictionary Objekte statt der benutzerdefinierten Klassen beschäftigen. Dies funktioniert oft besser als Sie denken. –

+0

Sie können Ihrer Klasse immer eine Methode 'initWithJSONObject: error:' (z. B. über eine Kategorie) hinzufügen. – CouchDeveloper

+0

@CouchDeveloper - 'initWithDictionary' ist wahrscheinlich allgemeiner. (Sie können den 'error:' parm einschließen, wenn es verdiente.) –

Antwort

12

Schließlich können wir dieses Problem leicht lösen mit JSONModel. Dies ist die beste Methode bisher. JSONModel ist eine Bibliothek, die Ihr Objekt basierend auf der Klasse generisch serialisiert/deserialisiert. Sie können sogar non-nsobject für Eigenschaften wie int, short und float verwenden. Es kann auch verschachtelte komplexe JSONs behandeln.

1) Deserialize Beispiel. Unter Bezugnahme auf die obigen Beispiel in Header-Datei:

#import "JSONModel.h" 

@interface Person : JSONModel 
@property (nonatomic, strong) NSString *firstName; 
@property (nonatomic, strong) NSString *lastName; 
@property (nonatomic, strong) NSNumber *age; 
@end 

@protocol Person; 

@interface Department : JSONModel 
@property (nonatomic, strong) NSMutableArray<Person> *accounting; 
@property (nonatomic, strong) NSMutableArray<Person> *sales; 
@end 

in Implementierungsdatei:

#import "JSONModelLib.h" 
#import "myJSONClass.h" 

NSString *responseJSON = /*from example*/; 
Department *department = [[Department alloc] initWithString:responseJSON error:&err]; 
if (!err) 
{ 
    for (Person *person in department.accounting) { 

     NSLog(@"%@", person.firstName); 
     NSLog(@"%@", person.lastName); 
     NSLog(@"%@", person.age);   
    } 

    for (Person *person in department.sales) { 

     NSLog(@"%@", person.firstName); 
     NSLog(@"%@", person.lastName); 
     NSLog(@"%@", person.age);   
    } 
} 

2) Serialize Beispiel. In Implementierungsdatei:

#import "JSONModelLib.h" 
#import "myJSONClass.h" 

Department *department = [[Department alloc] init]; 

Person *personAcc1 = [[Person alloc] init]; 
personAcc1.firstName = @"Uee"; 
personAcc1.lastName = @"Bae"; 
personAcc1.age = [NSNumber numberWithInt:22]; 
[department.accounting addOject:personAcc1]; 

Person *personSales1 = [[Person alloc] init]; 
personSales1.firstName = @"Sara"; 
personSales1.lastName = @"Jung"; 
personSales1.age = [NSNumber numberWithInt:20]; 
[department.sales addOject:personSales1]; 

NSLog(@"%@", [department toJSONString]); 

und das ist NSLog Ergebnis von Serialize Beispiel:

{ "accounting" : [{ "firstName" : "Uee", 
        "lastName" : "Bae", 
        "age"  : 22 } 
       ],        
    "sales"  : [{ "firstName" : "Sara", 
        "lastName" : "Jung", 
        "age"  : 20 } 
        ]} 
+1

Da Sie wissen, dass Modelle von json aus befüllt werden, können Sie eine 'initWithDictionary:' Methode einfügen, die das Mapping den entsprechenden Modellen überlassen. – Anupdas

+0

Ja, 'initWithDictionary' ist in diesem Fall ein ausgezeichneter Ansatz zur Initialisierung und hat den Vorteil, dass es auch in dem allgemeinen Fall verwendet werden kann, in dem das Objekt als Reaktion auf" lokale "Bedürfnisse initiert wird. Besonders mit der neuen '@ {...}' -Notation ist es einfach, ein Wörterbuch mit allen parms zu erstellen (falls JSON Ihnen kein Ready-Made aushändigt). Wenn Sie die JSONSerialization-Option verwenden, die veränderbare Objekte zur Verfügung stellt, können Sie das eingehende Wörterbuch ändern, um z. B. einen Schlüsselnamen zu ändern oder zusätzliche Parameter hinzuzufügen, die möglicherweise in JSON fehlen. –

+0

Danke für die Lösung, es hat meine Zeit und mein Gehirn gerettet – Abhishek

1

Sie müssen im Voraus wissen, welche Art von Objekt Sie deserializing werden. In diesem Fall werden Sie zu einer NSDictionary deserialisiert, die zwei Eigenschaften hat: "Accounting" und "Sales". Jede dieser Eigenschaften ist eine Instanz von NSArray. Die Arrays haben Instanzen von NSDictionary.

Da Sie wissen, was jedes dieser Objekte wirklich sind, nachdem Sie das JSON in native Objekte deserialisiert haben, können Sie neue Instanzen Ihrer Klassen aus den deserialisierten Objekten erstellen. Beispiel:

JSONDecoder decoder = [[JSONDecoder alloc] init]; 
NSObject notJSON = [decoder objectWithData:jsonData]; 
// where jsonData is an NSData representation of your JSON 
[decoder release]; 

Person person1 = (Person)[notJSON objectForKey:@"accounting"][0]; 

In diesem Beispiel sollten Sie in der Lage sein, auf einen generischen Deserializer zu extrapolieren. Das heißt, Sie möchten Ihre Daten durchlaufen, um eine tiefe Kopie Ihres "unbekannten" generischen Objekts zu einem "bekannten" spezifischen Objekt zu erstellen.

+1

tut mir leid dies ist nicht generisch. Siehe [this] (http://stackoverflow.com/questions/10515015/ios-json-serialization-for-nsobject-based-classes) als Referenz –

+1

Wie gesagt, und wie in Ihrer Referenz gesagt wurde, ist es nicht wirklich möglich darin total generisch zu sein. JSONKit dekodiert bereits generische native Objekte. Es liegt an Ihnen zu wissen, was sie wirklich sind. Wenn Sie nicht verlangen können, dass der JSON Ihnen (über eine Eigenschaft) sagt, dann müssen Sie ein bekanntes Format erwarten. –

+0

Ich habe dafür eine bessere Lösung, aber es kann immer noch nicht geschachtelt JSON bieten. Ein Layer-Nested JSON kein Problem. Damit kann ich jede Klasse weitergeben, die ich generisch serialisieren/deserialisieren möchte. Jetzt rufe ich jemanden an, wenn er eine Idee hat, wie man es für komplexe JSON macht. –

0

Vielleicht kann dies ein BWJSONMatcher helfen. Es hilft Ihnen, einfach eine JSON-Zeichenfolge oder ein JSON-Objekt mit einer Codezeile mit Ihrem Datenmodell abzugleichen.

... 
NSString *jsonString = @"{your-json-string}"; 
YourValueObject *dataModel = [YourValueObject fromJSONString:jsonString]; 

NSDictionary *jsonObject = @{your-json-object}; 
YourValueObject *dataModel = [YourValueObject fromJSONObject:jsonObject]; 
... 
YourValueObject *dataModel = instance-of-your-value-object; 
NSString *jsonString = [dataModel toJSONString]; 
NSDictionary *jsonObject = [dataModel toJSONObject]; 
...