Come deserializzare una stringa JSON in un NSDictionary? (Per iOS 5+)


154

Nella mia app iOS 5, ne ho una NSStringche contiene una stringa JSON. Vorrei deserializzare quella rappresentazione di stringa JSON in un NSDictionaryoggetto nativo .

 "{\"password\" : \"1234\",  \"user\" : \"andreas\"}"

Ho provato il seguente approccio:

NSDictionary *json = [NSJSONSerialization JSONObjectWithData:@"{\"2\":\"3\"}"
                                options:NSJSONReadingMutableContainers
                                  error:&e];  

Ma genera un errore di runtime. Che cosa sto facendo di sbagliato?

-[__NSCFConstantString bytes]: unrecognized selector sent to instance 0x1372c 
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[__NSCFConstantString bytes]: unrecognized selector sent to instance 0x1372c'

Quello era il mio approccio: NSDictionary * JSON = [NSJSONSerialization JSONObjectWithData: @ "{\" 2 \ ": \" 3 \ "}" opzioni: NSJSONReadingMutableContainers error: & e]; ottengo: 2011-12-22 17: 18: 59.300 Pi9000 [938: 13803] - [__ NSCFConstantString byte]: selettore non riconosciuto inviato all'istanza 0x1372c 2011-12-22 17: 18: 59.302 Pi9000 [938: 13803] *** Terminazione dell'app a causa dell'eccezione non rilevata 'NSInvalidArgumentException', motivo: '- [__ byte NSCFConstantString]: selettore non riconosciuto inviato all'istanza 0x1372c'
Andreas

Vedi la mia risposta che mostra due modi diversi per deserializzare una stringa JSON in un dizionario per Swift 3 e Swift 4.
Imanou Petit

Risposte:


335

Sembra che tu stia passando un NSStringparametro in cui dovresti passare un NSDataparametro:

NSError *jsonError;
NSData *objectData = [@"{\"2\":\"3\"}" dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:objectData
                                      options:NSJSONReadingMutableContainers 
                                        error:&jsonError];

@Abizem, quale errore posso usare qui? (op non lo menziona)

Grazie ... questo mi ha aiutato! e +1
Jayprakash Dubey,

Grazie, ha funzionato. Tuttavia, usando nilcome errore anziché &ein XCode 5
Michael Ho Chum

3
Mi piace l'Obiettivo C. Codifica la tua stringa in byte grezzi e poi decodificale in NSStrings e NSNumbers. Questo è ovvio, no?
vahotm,

1
@Abizern è comune ricevere JSON come una stringa da qualche parte al di fuori della tua applicazione
Chicowitz

37
NSData *data = [strChangetoJSON dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data
                                                             options:kNilOptions
                                                               error:&error];

Ad esempio hai un NSStringcarattere speciale con NSStringstrChangetoJSON. Quindi puoi convertire quella stringa in risposta JSON usando il codice sopra.


6

Ho creato una categoria dalla risposta @Abizern

@implementation NSString (Extensions)
- (NSDictionary *) json_StringToDictionary {
    NSError *error;
    NSData *objectData = [self dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *json = [NSJSONSerialization JSONObjectWithData:objectData options:NSJSONReadingMutableContainers error:&error];
    return (!json ? nil : json);
}
@end

Usalo in questo modo,

NSString *jsonString = @"{\"2\":\"3\"}";
NSLog(@"%@",[jsonString json_StringToDictionary]);

Comprendo che è consigliabile non testare errorin questi casi, ma invece verificare se il valore restituito è zero o meno prima di restituirlo. vale a dire return json ?: nil; Nitpick minore, ma vale la pena menzionare, penso.
Mike

@ Mike, penso che sia ok per verificare "errore" indipendentemente dal valore? Perché, se c'è un errore, stiamo tornando nilsubito.
Hemang,

Secondo i documenti di Apple "Quando si tratta di errori passati per riferimento, è importante testare il valore di ritorno del metodo per vedere se si è verificato un errore, come mostrato sopra. Non limitarsi a verificare se il puntatore dell'errore è stato impostato per puntare a un errore." developer.apple.com/library/ios/documentation/Cocoa/Conceptual/… Credo che ciò possa essere dovuto al fatto che potrebbero verificarsi casi in cui non si verifica un errore e il metodo restituisce un valore, ma la memoria a cui punta il puntatore dell'errore è scritto a, quindi pensi erroneamente che esista un errore.
Mike

Sono stato istruito in una mia precedente domanda: "La variabile non è inizializzata. Ciò significa che il valore a quell'indirizzo non è definito, quindi la modifica del valore non significherà nulla ... Dal momento che non esiste alcuna garanzia che il metodo non scriverà immondizia nell'indirizzo se non si verifica un errore, i documenti di Apple dicono che non è sicuro testare il valore della variabile di errore. " stackoverflow.com/questions/25558442/…
Mike

1
@ Mike, oh fantastico, buono a sapersi! Grazie per i riferimenti. Lo aggiornerò presto.
Hemang,

5

Con Swift 3 e Swift 4, Stringha un metodo chiamato data(using:allowLossyConversion:). data(using:allowLossyConversion:)ha la seguente dichiarazione:

func data(using encoding: String.Encoding, allowLossyConversion: Bool = default) -> Data?

Restituisce un dato contenente una rappresentazione della stringa codificata utilizzando una determinata codifica.

Con Swift 4, String's data(using:allowLossyConversion:)può essere usato insieme a JSONDecoder' s decode(_:from:)per deserializzare una stringa JSON in un dizionario.

Inoltre, con Swift 3 e Swift 4, Stringè data(using:allowLossyConversion:)anche possibile utilizzare JSONSerialization"s" insieme a " json​Object(with:​options:​)per deserializzare una stringa JSON in un dizionario.


# 1. Soluzione Swift 4

Con Swift 4, JSONDecoderha un metodo chiamato decode(_:from:). decode(_:from:)ha la seguente dichiarazione:

func decode<T>(_ type: T.Type, from data: Data) throws -> T where T : Decodable

Decodifica un valore di livello superiore del tipo specificato dalla rappresentazione JSON fornita.

Il codice Playground di seguito mostra come utilizzare data(using:allowLossyConversion:)e decode(_:from:)per ottenere un Dictionaryda un formato JSON String:

let jsonString = """
{"password" : "1234",  "user" : "andreas"}
"""

if let data = jsonString.data(using: String.Encoding.utf8) {
    do {
        let decoder = JSONDecoder()
        let jsonDictionary = try decoder.decode(Dictionary<String, String>.self, from: data)
        print(jsonDictionary) // prints: ["user": "andreas", "password": "1234"]
    } catch {
        // Handle error
        print(error)
    }
}

# 2. Soluzione Swift 3 e Swift 4

Con Swift 3 e Swift 4, JSONSerializationha un metodo chiamato json​Object(with:​options:​). json​Object(with:​options:​)ha la seguente dichiarazione:

class func jsonObject(with data: Data, options opt: JSONSerialization.ReadingOptions = []) throws -> Any

Restituisce un oggetto Foundation da determinati dati JSON.

Il codice Playground di seguito mostra come utilizzare data(using:allowLossyConversion:)e json​Object(with:​options:​)per ottenere un Dictionaryda un formato JSON String:

import Foundation

let jsonString = "{\"password\" : \"1234\",  \"user\" : \"andreas\"}"

if let data = jsonString.data(using: String.Encoding.utf8) {
    do {
        let jsonDictionary = try JSONSerialization.jsonObject(with: data, options: []) as? [String : String]
        print(String(describing: jsonDictionary)) // prints: Optional(["user": "andreas", "password": "1234"])
    } catch {
        // Handle error
        print(error)
    }
}

3

Utilizzo del codice Abizern per swift 2.2

let objectData = responseString!.dataUsingEncoding(NSUTF8StringEncoding)
let json = try NSJSONSerialization.JSONObjectWithData(objectData!, options: NSJSONReadingOptions.MutableContainers)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.