Возвращаемое значение NSDictionary objectForKey
-
06-07-2019 - |
Вопрос
Я использую 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, НСКФАррай объектов NSDictionary.(Да, я тоже чувствую здесь что-то забавное, но об этом чуть позже.)
Когда есть только один объект с именем X, я получаю обратно честный NSDictionary.
Так ...что мне следует сделать, чтобы это вел себя последовательно, независимо от того, сколько там X?
На первый взгляд, я думаю, что просто меняю результаты, чтобы НСаррай *, но что произойдет, если я захочу быстро пересчитать результаты?Прямо сейчас я делаю это:
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.
Решение
Я не знаком с 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, который позволяет вам контролировать его поведение в этом случае, и это будет предпочтительнее.
Другие советы
NSDictionary *results = [[dict objectForKey:@"OBJECTS"] objectForKey:@"X"];
и
NSDictionary *results = [dict valueForKeyPath:@"OBJECTS.X"];
Два вышеперечисленных абсолютно одинаковы.Первая операция немного дороже второй.
Вот что я в итоге сделал:
// 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 также может возвращаться словарь или массив. Тем не менее, я заглядываю внутрь словаря после назначения (OBJECTS.X).
Я не думаю, что ваши два примера кода,
NSDictionary *results = [[dict objectForKey:@"OBJECTS"] objectForKey:@"X"];
и
NSDictionary *results = [dict valueForKeyPath:@"OBJECTS.X"];
эквивалентны.Key-Value-Coding имеет некоторые дополнительные возможности для работы с коллекциями, которые могут вас сбить с толку.(Пример можно найти в сообщении блога Теокакао:NSArray и KVC Скотт Стивенсон.) Если вы вернетесь к прежнему, вы можете получить поведение, которого ожидаете.