Прямой доступ к значениям вложенного словаря в Objective-C

Есть ли способ прямого доступа к внутреннему массиву внешнего массива в Objective-C? Например, вызов внешнего источника данных возвращает следующий объект:

{
bio = "this is the profile.bio data";
"first_name" = John;
"last_name" = Doe;
location =     {
    name = "Any Town, Any State";
};
metadata =    {
    pictures =    {
        picture = "https://picture.mysite.com/picture.jpeg";
    }
}
}

Я хочу иметь доступ, например, к данным location.name или metadata.pictures.picture. Однако запись через точку, похоже, не работает. Например:

_gfbLocation = [result objectForKey:@"location.name"];
_gfbPicture = [result objectForKey:@"metadata.pictures.picture"];

Единственный способ получить доступ к этим данным — сначала установить содержимое внутренних массивов в объекты. Мысли?


person user455889    schedule 30.11.2010    source источник
comment
Между прочим, в некоторых языках (например, Javascript) эти структуры данных ключ/значение называются массивами, но в терминологии Objective-C они называются словарями (в частности, объектами NSDictionary). Если вы перефразируете свой вопрос, это поможет другим легче найти его (и ответ). Например, я бы предложил заголовок «Прямой доступ к вложенным значениям NSDictionary». Спасибо!   -  person Simon Whitaker    schedule 30.11.2010


Ответы (3)


Для таких вложенных ключей вы можете использовать keyPath. KeyPath — это просто набор ключей, соединенных точками. Вы можете использовать их для извлечения вложенных значений из объектов, поддерживающих кодирование значений ключа, включая такие объекты NSDictionary, как ваш. Итак, в вашем случае это должно работать:

[result valueForKeyPath:@"location.name"];

Дополнительные сведения о кодировании «ключ-значение» см. в документе Apple Руководство по кодированию значений ключа.

См. также этот связанный вопрос StackOverflow.

person Simon Whitaker    schedule 30.11.2010
comment
На случай, если кто-то ищет рабочую ссылку на Руководство по программированию Apple Key-Value Coding developer.apple.com/library/archive/documentation/Cocoa/ - person razibdeb; 15.08.2020

Используя правильный ответ Саймона Уитакера, я смог построить иерархию констант, вставив словарь в словарь в словарь. Ниже приведен пример исходного кода, модифицированный из моего реального исходного кода.

Это реальная проблема-решение. В моем конкретном случае целью была организация строк, идентифицирующих продукты, доступ к которым осуществляется через StoreKit для покупки в приложении в Apple App Store для iOS. Представьте, что наше приложение представляет контент из пары книг, одна о кошках, другая о собаках. Кроме того, наше приложение продает как сокращенную версию контента, так и полную. Обновление с сокращенного до полного означает третий продукт, «обновление». Каждая пара книг может быть переведена, в данном случае на английский и итальянский языки.

Глядя на строки, которые я пытаюсь отследить, вы можете подумать: «Почему этот парень просто не использует сами строки, а не занимается этой ерундой KVC?». Обратите внимание на вторую строку: English > Cats > Unabridged. Строка заканчивается добавленным символом подчеркивания. Это потому, что когда я использовал iTunesConnect для создания продуктов для покупки в приложении, я случайно создал этот элемент как «Расходуемый» вместо «Нерасходуемый». Apple не позволяет изменить идентификатор, даже если вы удалите указанный продукт. Таким образом, исходная строка не может быть использована; в качестве альтернативы я добавил подчеркивание в качестве обходного пути. Итак, дело в том, что эти строки произвольны и беспорядочны.

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

Внутри Xcode мне нужен лучший способ обращения к этим идентификаторам продукта.

// Using new literals syntax in later versions of Xcode 4 (& 5) to declare and populate a dictionary nested in a dictionary also in a dictionary.
NSDictionary *productIdentifiersHierarchy = @{
                                              @"en" : @{
                                                      @"cats" : @{
                                                              @"abridged" : @"com.example.My_App.cats_abridged_en",
                                                              @"unabridged" : @"com.example.My_App.cats_unabridged_en_",
                                                              @"upgrade" : @"com.example.My_App.cats_upgrade_en"
                                                              },
                                                      @"dogs" :  @{
                                                              @"abridged" : @"com.example.My_App.dogs_abridged_en",
                                                              @"unabridged" : @"com.example.My_App.dogs_unabridged_en",
                                                              @"upgrade" : @"com.example.My_App.dogs_upgrade_en"
                                                              }
                                                      },
                                              @"it" : @{
                                                      @"cats" : @{
                                                              @"abridged" : @"com.example.My_App.cats_abridged_it",
                                                              @"unabridged" : @"com.example.My_App.cats_unabridged_it",
                                                              @"upgrade" : @"com.example.My_App.cats_upgrade_it"
                                                              },
                                                      @"dogs" :  @{
                                                              @"abridged" : @"com.example.My_App.dogs_abridged_it",
                                                              @"unabridged" : @"com.example.My_App.dogs_unabridged_it",
                                                              @"upgrade" : @"com.example.My_App.dogs_upgrade_it"
                                                              }
                                                      }
                                              };

Вот как получить доступ к этим тройным вложенным словарям.

// Use KVC (Key-Value Coding) as a convenient way to access the nested dictionary structure.
NSLog( [productIdentifiersHierarchy valueForKeyPath:@"en.cats.abridged"],
NSLog( [productIdentifiersHierarchy valueForKeyPath:@"en.cats.unabridged"],
NSLog( [productIdentifiersHierarchy valueForKeyPath:@"en.cats.upgrade"],

NSLog( [productIdentifiersHierarchy valueForKeyPath:@"en.dogs.abridged"],
NSLog( [productIdentifiersHierarchy valueForKeyPath:@"en.dogs.unabridged"],
NSLog( [productIdentifiersHierarchy valueForKeyPath:@"en.dogs.upgrade"],

NSLog( [productIdentifiersHierarchy valueForKeyPath:@"it.cats.abridged"],
NSLog( [productIdentifiersHierarchy valueForKeyPath:@"it.cats.unabridged"],
NSLog( [productIdentifiersHierarchy valueForKeyPath:@"it.cats.upgrade"],

NSLog( [productIdentifiersHierarchy valueForKeyPath:@"it.dogs.abridged"] );
NSLog( [productIdentifiersHierarchy valueForKeyPath:@"it.dogs.unabridged"] );
NSLog( [productIdentifiersHierarchy valueForKeyPath:@"it.dogs.upgrade"] );
person Basil Bourque    schedule 16.11.2013
comment
Спасибо, Василий. Вопрос. Как вы можете использовать NSLog, не выполняя NSLog(@"%@", stuff); ?? - person Alex Zavatone; 09.12.2016
comment
При вызове NSLog(object) строка [описание объекта] автоматически вызывается за сценой. - person Neimsz; 14.03.2017

person    schedule
comment
№ используйте значениеForKeyPath. (см. ответ Саймона выше) - person jsd; 01.12.2010