Объединить NSDictionaries - NSUnknownKeyException

98
9

Я пытаюсь объединить два NSDictionaries:


NSDictionary *areaAttributes = [[area entity] attributesByName];
NSDictionary *gpsAttributes = [[gps entity] attributesByName];
NSMutableDictionary *combinedAttributes = [areaAttributes mutableCopy];
[combinedAttributes addEntriesFromDictionary:gpsAttributes];

Но получите следующую ошибку:


Terminating app due to uncaught exception 'NSUnknownKeyException', reason: 'The key 'latitude' is not defined for this NSKnownKeysDictionary'

latitude является ключом в gpsAttributes

спросил(а) 2013-01-15T08:34:00+04:00 7 лет, 8 месяцев назад
1
Решение
132

Проблема заключается в том, что вы не имеете дело с обычными словарями, но с NSKnownKeysDictionary, который является недокументированным типом, который Apple использует в различных частях Cocoa.


Если вы сбрасываете информацию об объекте ObjC из SDK, или, если это звучит слишком страшно, прочитайте чужую версию - вы можете видеть, что это на самом деле подкласс NSMutableDictionary, а не только NSDictionary, поэтому он уже изменен, поэтому ваш mutableCopy не нужен.


Что еще более важно, если вы прочитали, как протоколы NSCopying и NSMutableCopying являются не существует ничего, что требует mutableCopy вернуть вам нечто совместимое с его базовым классом; только чтобы он был изменчивым и неизменно совместимым с его базовым классом. Что раздражает.


Ответ здесь - создать новый изменяемый словарь и скопировать ключи из обоих объектов NSKnownKeysDictionary в это:

NSDictionary *areaAttributes = [[area entity] attributesByName];
NSDictionary *gpsAttributes = [[gps entity] attributesByName];
NSMutableDictionary *combinedAttributes = [NSMutableDictionary dictionaryWithCapacity:20];
[combinedAttributes addEntriesFromDictionary:areaAttributes];
[combinedAttributes addEntriesFromDictionary:gpsAttributes];

(Очевидно, что если вы беспокоитесь о производительности, вы либо хотите настроить этот 20, либо получить количество ключей от каждого словаря и пройти в общей сумме. Но обычно это не имеет значения.)


Возможно, вам интересно, почему Apple это сделала. Но если вы думаете об этом, это удобная вещь. У вас есть объект, который можно использовать как C struct внутри кишки некоторой библиотеки, но внешне выглядит так же, как NSDictionary. (Аналогичная цель, например, namedtuple в Python.) Методы, возвращающие их, предназначены для возврата NSDictionary, а не NSMutableDictionary, поэтому никто не знает, что у них ограниченный набор ключей. За исключением, конечно, если они звонят mutableCopy.


Вам также может быть интересно, как вы можете заранее об этом знать. Ну, ты действительно не можешь. Либо вы регистрируете типы объектов, вы пишете обработчик исключений и регистрируете исключение, либо разрешаете ему сбой и находите исключение в дампе сбоя. Или, альтернативно, вы можете защищаться и считаете, что любой словарь может дать вам бесполезный mutableCopy и неглубоко скопировать его в словарь типа, которым вы управляете.

ответил(а) 2013-01-16T00:55:00+04:00 7 лет, 8 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема