Возвращаемое значение NSDictionary objectForKey

Я использую json-framework для создания NSDictionary из ответа JSON. Это прекрасно работает.

Теперь внутри этой полезной нагрузки JSON находится один или несколько объектов - назовем их X. В XML это примерно так:

<OBJECTS>
  <X>
    ...
  </x>
  <X>
    ...
  </X>
  <X>
    ...
  </X>
</OBJECTS>

Когда я смотрю в вышеупомянутый объект NSDictionary для всех X, вот так:

NSDictionary *results = [[dict objectForKey:@"OBJECTS"] objectForKey:@"X"];

Или даже:

NSDictionary *results = [dict valueForKeyPath:@"OBJECTS.X"];

Согласно gdb, я получаю NSCFArray объектов NSDictionary. (Да, я тоже чувствую здесь что-то забавное, но об этом чуть позже.)

Когда есть только один объект с именем X, я получаю добротный NSDictionary.

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

На первый взгляд, мне показалось, что я просто изменил результаты на NSArray *, но что произойдет, если я захочу быстро пересчитать результаты? Прямо сейчас делаю так:

for (NSDictionary *result in results)

В случае NSCFArray (несколько X) я возвращаю отдельный NSDictionary для каждого X. В случае одного X я возвращаю один NSDictionary, за исключением того, что теперь моя перспектива на один уровень слишком глубока. Другими словами, вместо этого (надуманный пример):

(gdb) po results
<NSCFArray 0xd4a940>(
{
    foo =     {
        bar = "something";
    };
}
{
    foo =     {
        bar = "something else";
    };
}
)

Я получаю это:

(gdb) po results
{
    foo =     {
        bar = "something";
    };
}

Подсказки приветствуются / приветствуются! Вы даже можете спросить, нужно ли вообще разбирать это на части, но пока предположим, что эта поездка действительно необходима. (Тем не менее, я счастлив, что меня убедили в обратном, если кто-то будет достаточно твердо убежден в этом.)

В конце концов, я хочу иметь NSArray объектов NSDictionary.


person Joe D'Andrea    schedule 22.06.2009    source источник


Ответы (4)


Я не знаком с JSON или json-framework, но очевидно, что objectForKey не может использоваться для доступа к X, поскольку все они имеют один и тот же ключ.

Если вы знаете, что objectForKey: @ "OBJECTS" вернет либо NSDictionary (один элемент), либо NSArray NSDictionarys (несколько элементов X), вы можете сделать что-то вроде:

if ( ![results isKindOfClass:[NSArray class]] ) {
    results =[NSArray arrayWithObject:results];
}

Это даст вам стабильный результат, если вы точно понимаете, как будет вести себя json-framework. Это будет несколько хрупко, если элементы когда-либо вернут массив записей вместо NSDitionary, тогда все это развалится.

Может быть параметр конфигурации для json-framework, который позволяет вам контролировать его поведение в этом случае, и это было бы предпочтительнее.

person Peter N Lewis    schedule 22.06.2009
comment
Ах, я не понимал, что objectForKey нельзя использовать для доступа к нескольким экземплярам одного и того же ключа - спасибо! (Хотя похоже, что он делает именно это с NSCFArray ... или у меня галлюцинации ... или это просто неопределенное поведение, и мне повезло.) Я только что наткнулся на эту статью, и она обрабатывает случай нескольких X, как бы то ни было, так что я собираюсь попробовать следующее. Если это сработает, я обобщу исправление и сообщу здесь! iphonedevelopertips.com/cocoa/ - person Joe D'Andrea; 22.06.2009
comment
А вот функция-член, которую я использую. Обратите внимание, что он возвращает словарь или массив. Запрещая любые библиотечные моды, возможно, если я смогу просто проверить словарь, я могу при необходимости назначить его массиву из одного объекта. json-framework.googlecode.com/svn/trunk/documentation/ - person Joe D'Andrea; 22.06.2009
comment
Я ошибался насчет нескольких экземпляров одного и того же ключа. (Конечно, я имею в виду, что если так работает NSDictionary, то вот как это работает!) Оказывается, у нас действительно есть массив словарей, и это именно то, о чем вы предположили. :) - person Joe D'Andrea; 23.06.2009
comment
этот ответ помог мне по другому вопросу! Спасибо огромное - person Radu Ursache; 11.09.2016

NSDictionary *results = [[dict objectForKey:@"OBJECTS"] objectForKey:@"X"];

и

NSDictionary *results = [dict valueForKeyPath:@"OBJECTS.X"];

Вышеупомянутые два точно такие же. Первая операция немного дороже, чем вторая.

person prav    schedule 24.02.2010
comment
При использовании компиляции CLANG вы также можете использовать литералы objective-c dict [@OBJECTS] - clang.llvm .org / docs / ObjectiveCLiterals.html - person leviathan; 29.05.2013

Вот что я в итоге сделал:

// Get the JSON response and return the result:
NSString *jsonString = [NSString stringWithContentsOfURL:url];
NSDictionary *dict = [jsonString JSONValue];

// If OBJECTS.X gets a dictionary (one value), make an array of one.
id myObject = [dict valueForKeyPath:@"OBJECTS.X"];
if ([myObject isKindOfClass:[NSDictionary class]]) {
    results = [NSArray arrayWithObject:myObject];
} else {
    results = myObject;
}

Стоит отметить, что JSONValue также может возвращать словарь < em> или массив. Тем не менее, я заглядываю в словарь пост-присвоений (OBJECTS.X).

person Joe D'Andrea    schedule 22.06.2009
comment
В то же время стоит отметить, что предложение Питера более лаконичное! Мы знаем, что вернем словарь или массив, поэтому в случае Питера, если это не массив, это словарь, и мы можем просто создать из него массив с одним объектом. - person Joe D'Andrea; 23.06.2009

Я не думаю, что ваши два примера кода,

NSDictionary *results = [[dict objectForKey:@"OBJECTS"] objectForKey:@"X"];

и

NSDictionary *results = [dict valueForKeyPath:@"OBJECTS.X"];

эквивалентны. Key-Value-Coding имеет дополнительные возможности для работы с коллекциями, которые могут вас сбить с толку. (Пример можно найти в сообщении блога Theocacao: NSArray and KVC Скотта Стивенсона.) Если вы вернетесь к первому, вы можете получить ожидаемое поведение.

person Stig Brautaset    schedule 22.06.2009
comment
Спасибо! В этом конкретном случае результаты po показывают одно и то же для обоих примеров кода. (Честь скаута!) Поскольку у вас не может быть более одного X в данном словаре, каждый X в этом случае является собственным объектом NSDictionary. Однако ... может быть другая причина не использовать valueForKeyPath :. : -o belkadan.com/blog/ 2007/10 / - person Joe D'Andrea; 23.06.2009
comment
Я должен уточнить: если я смотрю на объект для ключевых ОБЪЕКТОВ, я получаю единственный словарь. Если я ищу там ключ X, that оказывается массивом словарей, поскольку в исходном XML / JSON есть несколько X. - person Joe D'Andrea; 23.06.2009