ฉันจะ deserialize สตริง JSON เป็น NSDictionary ได้อย่างไร (สำหรับ iOS 5+)


154

ในแอพ iOS 5 ของฉันฉันมีNSStringสตริงที่มีสตริง JSON ฉันต้องการยกเลิกการทำให้เป็นตัวแทนของสตริง JSON เป็นNSDictionaryวัตถุพื้นเมือง

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

ฉันลองวิธีต่อไปนี้:

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

แต่มันจะพ่นข้อผิดพลาดรันไทม์ ผมทำอะไรผิดหรือเปล่า?

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

นั่นเป็นวิธีของฉัน: NSDictionary * JSON = [NSJSONSerialization JSONObjectWithData: @ "{\" 2 \ ": ตัวเลือก:" "3 \"} ": ข้อผิดพลาด NSJSONReadingMutableContainers: & e]; ฉันได้รับ: 2011-12-22 17: 18: 59.300 Pi9000 [938: 13803] - [__ NSCFConstantString ไบต์]: ตัวเลือกที่ไม่รู้จักถูกส่งไปยังอินสแตนซ์ 0x1372c 2011-12-22 17: 18: 59.302 Pi9000 [938: 13803] *** การยกเลิกแอปเนื่องจากข้อยกเว้น 'NSInvalidArgumentException' ที่ยังไม่ได้ตรวจจับเหตุผล: '- [__ NSCFConstantString ไบต์]: ตัวเลือกที่ไม่รู้จักถูกส่งไปยังอินสแตนซ์ 0x1372c'
Andreas

ดูคำตอบของฉันที่แสดงสองวิธีที่แตกต่างกันในการยกเลิกการทำให้สตริง JSON เป็นพจนานุกรมสำหรับ Swift 3 และ Swift 4
Imanou Petit

คำตอบ:


335

ดูเหมือนว่าคุณกำลังผ่านNSStringพารามิเตอร์ที่คุณควรจะผ่านNSDataพารามิเตอร์:

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

@Abizem ฉันสามารถใช้ข้อผิดพลาดอะไรได้ที่นี่ (op ไม่ได้พูดถึงมัน)

ขอบคุณ ... อันนี้ช่วยได้! และ +1
Jayprakash Dubey

ขอบคุณมันใช้งานได้ อย่างไรก็ตามการใช้nilเป็นข้อผิดพลาดแทน&eใน XCode 5
Michael Ho Chum

3
ฉันชอบ Objective C. เข้ารหัสสตริงของคุณเป็นไบต์ดิบแล้วถอดรหัสกลับไปที่ NSStrings และ NSNumbers เห็นได้ชัดใช่มั้ย
vahotm

1
@Abizern เป็นเรื่องปกติที่จะได้รับ JSON เป็นสตริงจากที่อื่นที่ไม่ใช่ใบสมัครของคุณ
Chicowitz

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

ตัวอย่างเช่นคุณมีNSStringอักขระพิเศษในNSStringstrChangetoJSON จากนั้นคุณสามารถแปลงสตริงนั้นเป็นการตอบสนอง JSON โดยใช้โค้ดด้านบน


6

ฉันสร้างหมวดหมู่จากคำตอบ @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

ใช้มันแบบนี้

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

เป็นความเข้าใจของฉันว่าเป็นวิธีปฏิบัติที่ดีที่สุดที่จะไม่ทดสอบerrorในกรณีเหล่านี้ แต่ควรทดสอบว่าค่าส่งคืนเป็นศูนย์หรือไม่ก่อนส่งคืน เช่น return json ?: nil; nitpick เล็กน้อย แต่ก็น่าพูดถึง
Mike

@ ไมค์ฉันคิดว่ามันโอเคที่จะตรวจสอบ "ข้อผิดพลาด" โดยไม่คำนึงถึงค่าหรือไม่ เพราะถ้ามีข้อผิดพลาดเราจะกลับมาnilทันที
Hemang

เอกสารอ้างอิงของ Apple "เมื่อต้องจัดการกับข้อผิดพลาดที่ส่งผ่านโดยการอ้างอิงเป็นสิ่งสำคัญในการทดสอบค่าส่งคืนของวิธีการเพื่อดูว่ามีข้อผิดพลาดเกิดขึ้นดังที่แสดงไว้ด้านบนไม่เพียงแค่ทดสอบเพื่อดูว่า ข้อผิดพลาด " developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ ...... ฉันเชื่อว่านี่เป็นเพราะอาจมีบางกรณีที่ไม่มีข้อผิดพลาดเกิดขึ้นและวิธีการคืนค่า แต่หน่วยความจำที่ตัวชี้ข้อผิดพลาดชี้ไปที่คือ เขียนถึงดังนั้นคุณจึงคิดว่ามีข้อผิดพลาดอย่างผิด ๆ
Mike

ฉันได้รับการศึกษาในคำถามก่อนหน้านี้ของฉัน: "ตัวแปรไม่ได้กำหนดค่าเริ่มต้นซึ่งหมายความว่าค่าที่อยู่นั้นไม่ได้กำหนดดังนั้นการเปลี่ยนค่าจะไม่หมายถึงอะไรเลย ... เนื่องจากไม่มีการรับประกันวิธีที่จะไม่เขียน ขยะลงในที่อยู่หากไม่มีข้อผิดพลาดเกิดขึ้นเอกสารของ Apple บอกว่าไม่ปลอดภัยที่จะทดสอบค่าของตัวแปรข้อผิดพลาด " stackoverflow.com/questions/25558442/…
Mike

1
@ ไมค์ดีมากรู้ดี! ขอบคุณสำหรับการอ้างอิง ฉันจะอัปเดตในไม่ช้า
Hemang

5

กับสวิฟท์สวิฟท์ที่ 3 และ 4 มีวิธีการที่เรียกว่าString มีการประกาศดังต่อไปนี้:data(using:allowLossyConversion:)data(using:allowLossyConversion:)

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

ส่งคืนข้อมูลที่มีการแทนค่าสตริงที่เข้ารหัสโดยใช้การเข้ารหัสที่กำหนด

ด้วย Swift 4 Stringคุณdata(using:allowLossyConversion:)สามารถใช้ร่วมกับJSONDecoder's' decode(_:from:)เพื่อยกเลิกการจัดทำสตริง JSON ลงในพจนานุกรม

นอกจากนี้ด้วย Swift 3 และ Swift 4 Stringคุณdata(using:allowLossyConversion:)ยังสามารถใช้ร่วมกับJSONSerialization's json​Object(with:​options:​)เพื่อกำจัดสตริง JSON ลงในพจนานุกรม


# 1 โซลูชัน Swift 4

กับสวิฟท์ 4 มีวิธีการที่เรียกว่าJSONDecoder มีการประกาศดังต่อไปนี้:decode(_:from:)decode(_:from:)

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

ถอดรหัสค่าระดับบนสุดของประเภทที่กำหนดจากการเป็นตัวแทน JSON ที่กำหนด

รหัสสนามเด็กเล่นด้านล่างแสดงวิธีการใช้data(using:allowLossyConversion:)และวิธีdecode(_:from:)รับDictionaryจากการจัดรูปแบบ 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 โซลูชัน Swift 3 และ Swift 4

กับสวิฟท์สวิฟท์ที่ 3 และ 4 มีวิธีการที่เรียกว่าJSONSerialization มีการประกาศดังต่อไปนี้:json​Object(with:​options:​)json​Object(with:​options:​)

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

ส่งคืนวัตถุพื้นฐานจากข้อมูล JSON ที่กำหนด

รหัสสนามเด็กเล่นด้านล่างแสดงวิธีการใช้data(using:allowLossyConversion:)และวิธีjson​Object(with:​options:​)รับDictionaryจากการจัดรูปแบบ 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

ใช้รหัสAbizernสำหรับ swift 2.2

let objectData = responseString!.dataUsingEncoding(NSUTF8StringEncoding)
let json = try NSJSONSerialization.JSONObjectWithData(objectData!, options: NSJSONReadingOptions.MutableContainers)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.