Bagaimana cara menghapus deserialisasi string JSON menjadi NSDictionary? (Untuk iOS 5+)

154

Di aplikasi iOS 5 saya, saya punya NSStringyang berisi string JSON. Saya ingin deserialize bahwa representasi string JSON menjadi NSDictionaryobjek asli .

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

Saya mencoba pendekatan berikut:

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

Tapi itu melempar kesalahan runtime. Apa yang saya lakukan salah?

-[__NSCFConstantString bytes]: unrecognized selector sent to instance 0x1372c 
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[__NSCFConstantString bytes]: unrecognized selector sent to instance 0x1372c'
Andreas
sumber
Itulah pendekatan saya: NSDictionary * JSON = [NSJSONSerialization JSONObjectWithData: @ "{\" 2 \ ": \" 3 \ "}" pilihan: NSJSONReadingMutableContainers error: & e]; saya mendapatkan: 2011-12-22 17: 18: 59.300 Pi9000 [938: 13803] - [__ NSCFConstantString byte]: pemilih yang tidak dikenal dikirim ke instance 0x1372c 2011-12-22 17: 18: 59.302 Pi9000 [938: 13803] *** Mengakhiri aplikasi karena pengecualian 'NSInvalidArgumentException' tanpa alasan, alasan: '- [__ NSCFConstantString byte]: pemilih yang tidak dikenal dikirim ke instance 0x1372c'
Andreas
Lihat jawaban saya yang menunjukkan dua cara berbeda untuk
membatalkan desalisasi

Jawaban:

335

Sepertinya Anda mengirimkan NSStringparameter di mana Anda harus melewati NSDataparameter:

NSError *jsonError;
NSData *objectData = [@"{\"2\":\"3\"}" dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:objectData
                                      options:NSJSONReadingMutableContainers 
                                        error:&jsonError];
Abizern
sumber
@ Amiz, kesalahan apa yang bisa saya gunakan di sini? (op tidak menyebutkannya)
Terima kasih ... ini membantu! dan +1
Jayprakash Dubey
Terima kasih, ini berhasil. Namun, menggunakan nilsebagai kesalahan alih-alih &edalam XCode 5
Michael Ho Chum
3
Saya suka Objective C. Encode string Anda ke byte mentah dan kemudian decode kembali ke NSStrings dan NSNumber. Ini jelas, bukan?
vahotm
1
@Abizern biasa menerima JSON sebagai string dari suatu tempat di luar aplikasi Anda
Chicowitz
37
NSData *data = [strChangetoJSON dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data
                                                             options:kNilOptions
                                                               error:&error];

Misalnya Anda memiliki NSStringkarakter khusus di NSStringstrChangetoJSON. Kemudian Anda dapat mengonversi string itu menjadi respons JSON menggunakan kode di atas.

Desert Rose
sumber
6

Saya telah membuat kategori dari jawaban @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

Gunakan seperti ini,

NSString *jsonString = @"{\"2\":\"3\"}";
NSLog(@"%@",[jsonString json_StringToDictionary]);
Hemang
sumber
Ini pemahaman saya bahwa praktik terbaik untuk tidak menguji errordalam kasus ini, tetapi sebaliknya untuk menguji apakah nilai pengembaliannya nol atau tidak sebelum kembali. yaitu return json ?: nil; Minor nitpick, tetapi layak disebut, saya pikir.
Mike
@ Mike, saya pikir itu OK untuk memeriksa "kesalahan" terlepas dari nilainya? Karena, jika ada kesalahan maka kami akan nilsegera kembali .
Hemang
Menurut dokumen Apple "Ketika berhadapan dengan kesalahan yang diteruskan oleh referensi, penting untuk menguji nilai pengembalian metode untuk melihat apakah kesalahan terjadi, seperti yang ditunjukkan di atas. Jangan hanya menguji untuk melihat apakah penunjuk kesalahan diatur untuk menunjuk ke sebuah kesalahan. " developer.apple.com/library/ios/documentation/Cocoa/Conceptual/... Saya percaya ini karena mungkin ada kasus di mana kesalahan tidak terjadi dan metode mengembalikan nilai, tetapi memori tempat penunjuk kesalahan menunjuk adalah ditulis untuk, jadi Anda salah berpikir ada kesalahan.
Mike
Saya dididik dalam pertanyaan saya sebelumnya: "Variabel tidak diinisialisasi. Itu berarti nilai pada alamat itu tidak terdefinisi, jadi mengubah nilai tidak akan berarti apa-apa ... Karena tidak ada jaminan metode tidak akan menulis buang ke alamat jika kesalahan tidak terjadi, dokumen Apple mengatakan bahwa tidak aman untuk menguji nilai variabel kesalahan. " stackoverflow.com/questions/25558442/…
Mike
1
@ Mike, oh bagus, senang tahu! Terima kasih untuk referensi. Saya akan segera memperbarui ini.
Hemang
5

Dengan Swift 3 dan Swift 4, Stringmemiliki metode yang disebut data(using:allowLossyConversion:). data(using:allowLossyConversion:)memiliki deklarasi berikut:

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

Mengembalikan Data yang berisi representasi dari String yang dikodekan menggunakan pengkodean yang diberikan.

Dengan Swift 4, String's data(using:allowLossyConversion:)dapat digunakan bersama dengan JSONDecoder' s decode(_:from:)untuk deserialize string JSON ke dalam kamus.

Lebih lanjut, dengan Swift 3 dan Swift 4, String's data(using:allowLossyConversion:)juga dapat digunakan bersama dengan JSONSerialization' s json​Object(with:​options:​)untuk deserialize string JSON ke dalam kamus.


# 1. Solusi Swift 4

Dengan Swift 4, JSONDecodermemiliki metode yang disebut decode(_:from:). decode(_:from:)memiliki deklarasi berikut:

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

Mendekode nilai tingkat atas dari tipe yang diberikan dari representasi JSON yang diberikan.

Kode Playground di bawah ini menunjukkan cara menggunakan data(using:allowLossyConversion:)dan decode(_:from:)untuk mendapatkan Dictionarydari yang diformat 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. Solusi Swift 3 dan Swift 4

Dengan Swift 3 dan Swift 4, JSONSerializationmemiliki metode yang disebut json​Object(with:​options:​). json​Object(with:​options:​)memiliki deklarasi berikut:

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

Mengembalikan objek Foundation dari data JSON yang diberikan.

Kode Playground di bawah ini menunjukkan cara menggunakan data(using:allowLossyConversion:)dan json​Object(with:​options:​)untuk mendapatkan Dictionarydari yang diformat 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)
    }
}
Imanou Petit
sumber
3

Menggunakan kode Abizern untuk swift 2.2

let objectData = responseString!.dataUsingEncoding(NSUTF8StringEncoding)
let json = try NSJSONSerialization.JSONObjectWithData(objectData!, options: NSJSONReadingOptions.MutableContainers)
IOS Singh
sumber