2013-02-19 10 views
9

Qualcuno ha idea di come serializzare JSON nidificato basato sulla classe NSObject? C'è una discussione per serializzare semplice JSON here, ma non è abbastanza generico per soddisfare JSON nidificati complessi.iOS: serializza/deserializza JSON complesso genericamente dalla classe NSObject

immaginare questo è il risultato di JSON:

{ "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 } 
        ]} 

Da questa classe:

@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 

Come serializzare/deserializzare loro in base alla classe generica?

EDIT

Attualmente sono in grado di generare carico utile come questo sulla base di qualsiasi classe:

NSMutableDictionary *Payload = [self serialize:objClass]; 

Ma non è adatto nidificato JSON complesso. Qualcuno ha una soluzione migliore per questo? This library per C# gestisce serialize/deserialze in base alla classe dell'oggetto. Voglio riprodurre qualcosa dello stesso basato su NSObject

+0

Un modo per farlo non è: basta andare avanti e gestire gli oggetti NSDictionary invece delle classi personalizzate. Questo spesso funziona meglio di quanto si pensi. –

+0

È sempre possibile aggiungere un metodo alla classe 'initWithJSONObject: error:' (tramite una categoria, ad esempio). – CouchDeveloper

+0

@CouchDeveloper - 'initWithDictionary' è probabilmente più generale. (Puoi includere l'errore ': parm se è meritato.) –

risposta

12

Finalmente possiamo risolvere facilmente questo problema usando JSONModel. Questo è il miglior metodo finora. JSONModel è una libreria che serializza/deserializza genericamente il tuo oggetto in base alla classe. È anche possibile utilizzare non-nsobject basato su proprietà come int, short e float. Può anche soddisfare i JSON complessi nidificati.

1) Deserialize example. Con riferimento all'esempio di cui sopra, nel file di intestazione:

#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 

nel file di implementazione:

#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 Esempio. Nel file di implementazione:

#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]); 

E questo è risultato NSLog da Serialize esempio:

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

Poiché si sa che i modelli verranno popolati da json, è possibile includere un metodo 'initWithDictionary:' che lascia la mappatura ai rispettivi modelli. – Anupdas

+0

Sì, 'initWithDictionary' è un approccio eccellente all'inizializzazione in questo caso e ha il vantaggio che può essere utilizzato anche nel caso generale in cui l'oggetto viene inserito in risposta a esigenze" locali ". Soprattutto con la nuova notazione '@ {...}' è facile creare un dizionario con tutti i parm in esso contenuti (nel caso in cui JSON non ti consegna un ready-made). Inoltre, se si utilizza l'opzione JSONSerialization che fornisce oggetti mutabili, è possibile modificare il dizionario in entrata, ad esempio, modificare un nome chiave o aggiungere ulteriori parm che potrebbero mancare dal JSON. –

+0

Grazie per la soluzione, mi ha salvato tempo e cervello – Abhishek

1

È necessario sapere in anticipo quale tipo di oggetto verrà deserializzato. In questo caso, stai per deserializzare su uno NSDictionary con due proprietà: "contabilità" e "vendite". Ognuna di queste proprietà sarà un'istanza di NSArray. Gli array avranno istanze di NSDictionary.

Poiché si sa che ognuno di questi oggetti è veramente, una volta deserializzato il JSON in oggetti nativi è possibile creare nuove istanze delle classi fuori dagli oggetti deserializzati. Ad esempio:

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]; 

Dato questo esempio, dovresti essere in grado di estrapolare a un deserializzatore più generico. Cioè, vorrai scorrere i tuoi dati per creare una copia profonda del tuo oggetto generico "sconosciuto" su un oggetto specifico "conosciuto".

+1

mi dispiace questo non è generico Vedi [this] (http://stackoverflow.com/questions/10515015/ios-json-serialization-for-nsobject-based-classes) per riferimento –

+1

Come ho detto, e come è stato detto nel tuo riferimento, non è davvero possibile essere totalmente generico in questo JSONKit è già in decodifica per oggetti nativi generici. Sta a te sapere cosa sono veramente. Se non puoi richiedere al JSON di dirti (attraverso alcune proprietà), allora devi aspettarti un formato noto. –

+0

Ho creato una soluzione migliore per questo, ma non è ancora in grado di soddisfare JSON annidato. Un JSON nidificato a livello nessun problema. Con ciò posso passare qualsiasi classe che desidero serializzare/deserializzare genericamente. Ora chiamo chiunque per aiuto se hanno qualche idea su come farlo per JSON complesso –

0

Forse questo si può fare a BWJSONMatcher. Consente di associare facilmente una stringa JSON o un oggetto JSON con il modello di dati con una riga di codice.

... 
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]; 
... 
Problemi correlati