Deserializzazione della NSString locale di JSON in oggetti tramite RestKit (nessun download dalla rete)

StackOverflow https://stackoverflow.com/questions/8873607

  •  28-10-2019
  •  | 
  •  

Domanda

È possibile deserializzare un file NSString di JSON in oggetti tramite RestKit?Ho controllato l'elenco delle API Qui e non sono riuscito a trovare qualcosa che servisse a questo scopo.Il più vicino che ho trovato sono le varie classi parser che restituiscono NSDictionary dopo aver analizzato l'input.Presumo che RestKit utilizzi questi parser dopo aver scaricato la risposta, quindi penso che la funzionalità sia disponibile da qualche parte in RestKit ma non esposta pubblicamente.

Se non mi manca nulla e questa funzionalità non è esposta, quali sarebbero le alternative?Due ovvi non sembrano molto promettenti:Ottieni il risultato NSDictionary e prova a deserializzarmi (reimplementando efficacemente RestKit) o ​​prova ad immergerti nel sorgente RestKit e vedere se questo può essere in qualche modo esposto (sembra noioso e soggetto a errori).

Grazie in anticipo per qualsiasi aiuto.

PS:L'idea è che una proprietà stringa su un oggetto deserializzato sia in realtà la rappresentazione JSON di un altro insieme di oggetti (JSON incorporato in un certo senso) e venga deserializzata su richiesta durante il runtime.

È stato utile?

Soluzione

Abbastanza semplice":

NSString *stringJSON;
...

RKJSONParserJSONKit *parser;
NSError *error= nil;
parser= [[[RKJSONParserJSONKit alloc] init] autorelease]; 
MyManagedObject *target;
target= [MyManagedObject object];

NSDictionary *objectAsDictionary;
RKObjectMapper* mapper;
objectAsDictionary= [parser objectFromString:stringJSON error:&error];
mapper = [RKObjectMapper mapperWithObject:objectAsDictionary 
                          mappingProvider:[RKObjectManager sharedManager].mappingProvider];
mapper.targetObject = target;
RKObjectMappingResult* result = [mapper performMapping];
NSLog(@"%@", [result asObject]);

Altri suggerimenti

Come di RestKit 0.20.0-pre2

NSString* JSONString = @"{ \"name\": \"The name\", \"number\": 12345}";
NSString* MIMEType = @"application/json";
NSError* error;
NSData *data = [JSONString dataUsingEncoding:NSUTF8StringEncoding];
id parsedData = [RKMIMETypeSerialization objectFromData:data MIMEType:MIMEType error:&error];
if (parsedData == nil && error) {
    // Parser error...
}

AppUser *appUser = [[AppUser alloc] init];

NSDictionary *mappingsDictionary = @{ @"someKeyPath": someMapping };
RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:parsedData mappingsDictionary:mappingsDictionary];
mapper.targetObject = appUser;
NSError *mappingError = nil;
BOOL isMapped = [mapper execute:&mappingError];
if (isMapped && !mappingError) {
    // Yay! Mapping finished successfully
    NSLog(@"mapper: %@", [mapper representation]);
    NSLog(@"firstname is %@", appUser.firstName);
}

Funziona con Restkit 0.21.0:

NSString* jsonFilePath = [[NSBundle mainBundle] pathForResource:@"fileName"
                                                 ofType:@"json"];

NSString* JSONString = [NSString stringWithContentsOfFile:jsonFilePath
                                              encoding:NSUTF8StringEncoding
                                                 error:NULL];


NSError* error;
NSData *data = [JSONString dataUsingEncoding:NSUTF8StringEncoding];
id parsedData = [RKMIMETypeSerialization objectFromData:data MIMEType:RKMIMETypeJSON error:&error];
if (parsedData == nil && error) {
    // Parser error...
}

//_objectManager is RKObjectManager instance
NSMutableDictionary *mappingsDictionary = [[NSMutableDictionary alloc] init];
for (RKResponseDescriptor *descriptor in _objectManager.responseDescriptors) {
    [mappingsDictionary setObject:descriptor.mapping forKey:descriptor.keyPath];
}

RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:parsedData mappingsDictionary:mappingsDictionary];
NSError *mappingError = nil;
BOOL isMapped = [mapper execute:&mappingError];
if (isMapped && !mappingError) {
    NSLog(@"result %@",[mapper mappingResult]);
}

Funziona con Restkit 0.20, utilizzando Entità di dati principali.Si basa sulla soluzione fornita da @innerself

NSString* jsonFilePath = [[NSBundle mainBundle] pathForResource:@"info-base"
                                                         ofType:@"json"];

NSString* JSONString = [NSString stringWithContentsOfFile:jsonFilePath
                                                 encoding:NSUTF8StringEncoding
                                                    error:NULL];


NSError *error = nil;

NSData *data = [JSONString dataUsingEncoding:NSUTF8StringEncoding];
id parsedData = [RKMIMETypeSerialization objectFromData:data MIMEType:RKMIMETypeJSON error:&error];
if (parsedData == nil && error) {
    // Parser error...
    NSLog(@"parse error");
}

//_objectManager is RKObjectManager instance
NSMutableDictionary *mappingsDictionary = [[NSMutableDictionary alloc] init];
for (RKResponseDescriptor *descriptor in [RKObjectManager sharedManager].responseDescriptors) {

    [mappingsDictionary setObject:descriptor.mapping forKey:descriptor.keyPath];
}

RKManagedObjectMappingOperationDataSource *datasource = [[RKManagedObjectMappingOperationDataSource alloc]
                                                         initWithManagedObjectContext:[RKManagedObjectStore defaultStore].persistentStoreManagedObjectContext
                                                                                cache:[RKManagedObjectStore defaultStore].managedObjectCache];

RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:parsedData
                                                           mappingsDictionary:mappingsDictionary];
[mapper setMappingOperationDataSource:datasource];

NSError *mappingError = nil;
BOOL isMapped = [mapper execute:&mappingError];
if (isMapped && !mappingError) {
    // data is in [mapper mappingResult]
}

Puoi vedere come RestKit lo fa internamente nel file RKManagedObjectResponseMapperOperation classe.

Ci sono tre fasi di questa operazione.

Il primo è analizzare la stringa JSON in NSDictionarys, NSArrays, ecc.Questa è la parte più semplice.

id parsedData = [RKMIMETypeSerialization objectFromData:data
                                               MIMEType:RKMIMETypeJSON
                                                  error:error];

Successivamente è necessario eseguire un'operazione di mappatura per convertire questi dati nei tuoi NSManagedObjects.Questo è un po' più complicato.

__block NSError *blockError = nil;
__block RKMappingResult *mappingResult = nil;
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
operationQueue.maxConcurrentOperationCount = 1;

[[RKObjectManager sharedManager].managedObjectStore.persistentStoreManagedObjectContext performBlockAndWait:^{

Ricordati di sostituire questo dizionario con le tue mappature.Il tasto [NSNull null] mappa questo oggetto dalla radice.

    NSDictionary *mappings = @{[NSNull null]: [jotOfflineRequestStatus mapping]};

    RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:parsedData
                                                               mappingsDictionary:mappings];

    RKManagedObjectMappingOperationDataSource *dataSource = [[RKManagedObjectMappingOperationDataSource alloc]
                                                             initWithManagedObjectContext:[RKManagedObjectStore defaultStore].persistentStoreManagedObjectContext
                                                             cache:[RKManagedObjectStore defaultStore].managedObjectCache];
    dataSource.operationQueue = operationQueue;
    dataSource.parentOperation = mapper;
    mapper.mappingOperationDataSource = dataSource;

    [mapper start];
    blockError = mapper.error;
    mappingResult = mapper.mappingResult;
}];

Ora devi eseguire le attività che sono state inserite nell'operazioneQueue che abbiamo creato.È in questa fase che vengono effettuate le connessioni agli NSManagedObject esistenti.

if ([operationQueue operationCount]) {
    [operationQueue waitUntilAllOperationsAreFinished];
}

Una risposta più orientata a iOS 5+:

NSString* JSONString = jsonString;
NSString* MIMEType = @"application/json";
NSError* error = nil;
id<RKParser> parser = [[RKParserRegistry sharedRegistry] parserForMIMEType:MIMEType];
id parsedData = [parser objectFromString:JSONString error:&error];
if (parsedData == nil && error) {
    NSLog(@"ERROR: JSON parsing error");
}

RKObjectMappingProvider* mappingProvider = [RKObjectManager sharedManager].mappingProvider;
RKObjectMapper* mapper = [RKObjectMapper mapperWithObject:parsedData mappingProvider:mappingProvider];
RKObjectMappingResult* result = [mapper performMapping];
if (result) {

    NSArray *resultArray = result.asCollection;

    MyObject *object = [resultArray lastObject];
    NSLog(@"My Object: %@", object);
}

Per Restkit 0.22, puoi utilizzare questo codice.Ciò restituisce un RKMappingResult in cui è possibile enumerare gli oggetti dopo la mappatura utilizzando la proprietà .array.

- (RKMappingResult *)mapJSONStringWithString:(NSString *)jsonString
{
     RKMappingResult *result = nil;

     NSError* error;
     NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
     id parsedData = [RKMIMETypeSerialization objectFromData:data MIMEType:RKMIMETypeJSON error:&error];
     if (parsedData == nil && error) {
        NSLog(@"json mapping error");
     }

     NSDictionary *mappingsDictionary = @{@"":[CustomMappingClass getMappingForUsers]};

     ObjectClass *obj = [ObjectClass new];
     RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:parsedData mappingsDictionary:mappingsDictionary];
     NSError *mappingError = nil;
     mapper.targetObject = obj;
     BOOL isMapped = [mapper execute:&mappingError];
     if (isMapped && !mappingError) {
         result = [mapper mappingResult];
     }

    return result;
}

Non è questo quello che stai cercando? http://restkit.org/api/0.10.0/Classes/RKJSONParserJSONKit.html

A giudicare dalle opinioni senza risposta, sembra che questa funzionalità non esista ancora in RestKit.Invece di dedicare più tempo a cercare di capire come eseguire la mappatura, ho scritto il mio mappatore utilizzando l'output del parser JsonKit e rimosso la dipendenza da RestKit (utilizzando le classi integrate per l'attività di rete).In questo momento il mio mappatore non è generico (ha alcune dipendenze da come sono disposti gli oggetti e dai loro nomi in json) ma funziona per gli scopi del progetto.Potrei tornare più tardi e trasformarlo in una libreria di mappatura di oggetti più generica in seguito.

MODIFICARE:Questa risposta è stata selezionata perché non c'erano altre risposte alla data di questa risposta (21 gennaio 2012).Da allora, ho smesso di lavorare su iOS e non ho mai più posto questa domanda.Ora seleziono la risposta di Ludovic a causa del commento di un altro utente e dei voti positivi per quella risposta.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top