Как использовать NSJSONSerialization - PullRequest
152 голосов
/ 02 декабря 2011

У меня есть строка JSON (из PHP json_encode(), которая выглядит следующим образом:

[{"id": "1", "name":"Aaa"}, {"id": "2", "name":"Bbb"}]

Я хочу разобрать это в некую структуру данных для моего приложения для iPhone. Полагаю, для меня лучше всего иметь массив словарей, поэтому 0-й элемент в массиве - это словарь с ключами "id" => "1" и "name" => "Aaa".

Я не понимаю, как NSJSONSerialization хранит данные. Вот мой код:

NSError *e = nil;
NSDictionary *JSON = [NSJSONSerialization 
    JSONObjectWithData: data 
    options: NSJSONReadingMutableContainers 
    error: &e];

Это просто то, что я видел в качестве примера на другом сайте. Я пытался прочитать объект JSON, распечатав количество элементов и тому подобное, но я всегда получаю EXC_BAD_ACCESS.

Как мне использовать NSJSONSerialization, чтобы проанализировать JSON выше и превратить его в структуру данных, о которой я говорил?

Ответы [ 11 ]

206 голосов
/ 02 декабря 2011

Ваш корневой объект json - это не словарь, а массив:

[{"id": "1", "name":"Aaa"}, {"id": "2", "name":"Bbb"}]

Это может дать вам четкое представление о том, как с этим справиться:

NSError *e = nil;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &e];

if (!jsonArray) {
  NSLog(@"Error parsing JSON: %@", e);
} else {
   for(NSDictionary *item in jsonArray) {
      NSLog(@"Item: %@", item);
   }
}
72 голосов
/ 27 апреля 2012

Это мой код для проверки, является ли полученный json массивом или словарем:

NSError *jsonError = nil;
id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&jsonError];

if ([jsonObject isKindOfClass:[NSArray class]]) {
    NSLog(@"its an array!");
    NSArray *jsonArray = (NSArray *)jsonObject;
    NSLog(@"jsonArray - %@",jsonArray);
}
else {
    NSLog(@"its probably a dictionary");
    NSDictionary *jsonDictionary = (NSDictionary *)jsonObject;
    NSLog(@"jsonDictionary - %@",jsonDictionary);
}

Я пробовал это для параметров: kNilOptions и NSJSONReadingMutableContainers и работает правильно для обоих.

Очевидно, что реальный код не может быть таким, когда я создаю указатель NSArray или NSDictionary в блоке if-else.

27 голосов
/ 02 декабря 2011

Это работает для меня.Ваш data объект, вероятно, nil, и, как отметил rckoenes, корневой объект должен быть (изменяемым) массивом.Смотрите этот код:

NSString *jsonString = @"[{\"id\": \"1\", \"name\":\"Aaa\"}, {\"id\": \"2\", \"name\":\"Bbb\"}]";
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *e = nil;
NSMutableArray *json = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&e];
NSLog(@"%@", json);

(мне пришлось экранировать кавычки в строке JSON с обратной косой чертой.)

8 голосов
/ 02 декабря 2011

Ваш код выглядит нормально, за исключением результата NSArray, а не NSDictionary, вот пример:

Первые две строки просто создают объект данных с JSON, такой же, как выполучит чтение из сети.

NSString *jsonString = @"[{\"id\": \"1\", \"name\":\"Aaa\"}, {\"id\": \"2\", \"name\":\"Bbb\"}]";
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];

NSError *e;
NSMutableArray *jsonList = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&e];
NSLog(@"jsonList: %@", jsonList);

Содержимое NSLog (список словарей):

jsonList: (
           {
               id = 1;
               name = Aaa;
           },
           {
               id = 2;
               name = Bbb;
           }
           )
6 голосов
/ 04 апреля 2013
[{"id": "1", "name":"Aaa"}, {"id": "2", "name":"Bbb"}]

В приведенных выше данных JSON вы показываете, что у нас есть массив, содержащий количество словарей.

Вам нужно использовать этот код для анализа:

NSError *e = nil;
NSArray *JSONarray = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &e];
        for(int i=0;i<[JSONarray count];i++)
        {
            NSLog(@"%@",[[JSONarray objectAtIndex:i]objectForKey:@"id"]);
             NSLog(@"%@",[[JSONarray objectAtIndex:i]objectForKey:@"name"]);
        }

Для быстрых 3/3 +

   //Pass The response data & get the Array
    let jsonData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [AnyObject]
    print(jsonData)
    // considering we are going to get array of dictionary from url

    for  item  in jsonData {
        let dictInfo = item as! [String:AnyObject]
        print(dictInfo["id"])
        print(dictInfo["name"])
    }
3 голосов
/ 27 ноября 2013

Следующий код выбирает объект JSON с веб-сервера и анализирует его в NSDictionary.Я использовал API openweathermap, который возвращает простой ответ JSON для этого примера.Для простоты этот код использует синхронные запросы.

   NSString *urlString   = @"http://api.openweathermap.org/data/2.5/weather?q=London,uk"; // The Openweathermap JSON responder
   NSURL *url            = [[NSURL alloc]initWithString:urlString];
   NSURLRequest *request = [NSURLRequest requestWithURL:url];
   NSURLResponse *response;
   NSData *GETReply      = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
   NSDictionary *res     = [NSJSONSerialization JSONObjectWithData:GETReply options:NSJSONReadingMutableLeaves|| NSJSONReadingMutableContainers error:nil];
   Nslog(@"%@",res);
2 голосов
/ 18 июня 2013

@ rckoenes уже показал вам, как правильно получать данные из строки JSON.

На вопрос, который вы задали: EXC_BAD_ACCESS почти всегда возникает, когда вы пытаетесь получить доступ к объекту после того, как он был [auto-]вышел.Это не относится к JSON-де-сериализации, а скорее просто связано с получением объекта и последующим доступом к нему после его освобождения.Факт, что это пришло через JSON, не имеет значения.

Есть много-много страниц, описывающих, как отладить это - вы хотите Google (или SO) obj-c zombie objects и, в частности, NSZombieEnabled, который окажется неоценимым для вас, помогая определить источник ваших объектов зомби.(«Зомби» - это то, что называется, когда вы отпускаете объект, но сохраняете указатель на него и пытаетесь ссылаться на него позже.)

1 голос
/ 19 октября 2016

ПРИМЕЧАНИЕ: для Swift 3 . Ваша строка JSON возвращает массив вместо словаря. Пожалуйста, попробуйте следующее:

        //Your JSON String to be parsed
        let jsonString = "[{\"id\": \"1\", \"name\":\"Aaa\"}, {\"id\": \"2\", \"name\":\"Bbb\"}]";

        //Converting Json String to NSData
        let data = jsonString.data(using: .utf8)

        do {

            //Parsing data & get the Array
            let jsonData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [AnyObject]

            //Print the whole array object
            print(jsonData)

            //Get the first object of the Array
            let firstPerson = jsonData[0] as! [String:Any]

            //Looping the (key,value) of first object
            for (key, value) in firstPerson {
                //Print the (key,value)
                print("\(key) - \(value) ")
            }

        } catch let error as NSError {
            //Print the error
            print(error)
        }
1 голос
/ 15 июня 2015

Swift 2.0 на Xcode 7 (бета) с блоком do / try / catch:

// MARK: NSURLConnectionDataDelegate

func connectionDidFinishLoading(connection:NSURLConnection) {
  do {
    if let response:NSDictionary = try NSJSONSerialization.JSONObjectWithData(receivedData, options:NSJSONReadingOptions.MutableContainers) as? Dictionary<String, AnyObject> {
      print(response)
    } else {
      print("Failed...")
    }
  } catch let serializationError as NSError {
    print(serializationError)
  }
}
0 голосов
/ 18 августа 2015

Проблема, похоже, связана с автоматическим выпуском объектов.NSJSONSerialization JSONObjectWithData, очевидно, создает некоторые автоматически выпущенные объекты и передает их вам.Если вы попытаетесь перенести это в другой поток, он не будет работать, поскольку его нельзя освободить в другом потоке.

Может быть, уловка заключается в том, чтобы попытаться создать изменяемую копию этого словаря или массива и использовать ее.

NSError *e = nil;
id jsonObject = [NSJSONSerialization 
JSONObjectWithData: data 
options: NSJSONReadingMutableContainers 
error: &e] mutableCopy];

Обработка NSDictionary как NSArray не приведет к исключению Плохого доступа, но вместо этого, вероятно, произойдет сбой при вызове метода.

Кроме того, параметры могут не иметь значения здесьно лучше дать NSJSONReadingMutableContainers |NSJSONReadingMutableContainers |NSJSONReadingAllowFragments, но даже если они являются автоматически выпущенными объектами, это может не решить эту проблему.

...