Як я деріаріалізую рядок 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 error: & 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'
Андреас

Дивіться мою відповідь, яка показує два різні способи знецінити рядок 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, яку помилку я можу тут використати? (оп не згадує про це)

Дякую ... цей допоміг! та +1
Джайпракаш Дабі

Спасибі, спрацювало. Однак, використовуючи nilяк помилку замість &eXCode 5
Michael Ho Chum

3
Мені подобається ціль 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; Незначна нитка, але варто згадати, я думаю.
Майк

@Mike, я думаю, що гаразд перевірити "помилку" незалежно від значення? Тому що, якщо є помилка, ми повертаємося nilодразу.
Хеман

Відповідно до документів Apple: "При роботі з помилками, переданими посиланням, важливо перевірити значення повернення методу, щоб побачити, чи сталася помилка, як показано вище. Не просто перевіряйте, чи встановлено вказівку помилки на помилка." developer.apple.com/library/ios/documentation/Cocoa/Conceptual/… Я вважаю, що це тому, що можуть бути випадки, коли помилка не виникає і метод повертає значення, але пам'ять, на яку вказує вказівка ​​на помилку, є написано на, тож ви помилково вважаєте, що існує помилка.
Майк

Мене навчали в попередньому моєму питанні: "Змінна неініціалізована. Це означає, що значення за цією адресою не визначено, тому зміна значення нічого не означатиме ... Оскільки немає гарантії, метод не запише сміття в адресу, якщо помилка не трапляється, документи Apple кажуть, що перевірити значення змінної помилки небезпечно ". stackoverflow.com/questions/25558442/…
Майк

1
@Mike, чудово, добре знати! Дякую за довідку. Я скоро це оновлю.
Хеман

5

З Swift 3 і Swift 4 Stringє метод, який називається data(using:allowLossyConversion:). data(using:allowLossyConversion:)має таку заяву:

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

Повертає Дані, що містять подання String, закодованого за допомогою заданого кодування.

З Swift 4, String's data(using:allowLossyConversion:)можна використовувати разом із JSONDecoder' s decode(_:from:), щоб деріаріалізувати рядок JSON у словник.

Крім того, з Swift 3 та Swift 4, String's data(using:allowLossyConversion:)також можна використовувати разом із JSONSerialization' s json​Object(with:​options:​), щоб деріаріалізувати рядок JSON у словник.


№1. Рішення Swift 4

У Swift 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

З Swift 3 і Swift 4 JSONSerializationє метод, який називається json​Object(with:​options:​). json​Object(with:​options:​)має таку заяву:

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

Повертає об'єкт Foundation із даних 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 для швидкого 2.2

let objectData = responseString!.dataUsingEncoding(NSUTF8StringEncoding)
let json = try NSJSONSerialization.JSONObjectWithData(objectData!, options: NSJSONReadingOptions.MutableContainers)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.