iOS - отличить NSDictionary от NSMutableDictionary? - PullRequest
2 голосов
/ 11 февраля 2012

У меня есть следующий фрагмент кода:

NSString* value = @"value";
NSString* key = @"key";
NSMutableDictionary* foo = [NSMutableDictionary dictionary];
NSDictionary* bar = [NSDictionary dictionary];
NSAssert([bar isKindOfClass: [NSMutableDictionary class]], @"");   // passes the assert as both are NSCFDictionary;
NSAssert([bar respondsToSelector: @selector(setValue:forKey:)], @"");   // passes the assert because it NSCFDictionary does respond to the selector
[foo setValue:value forKey:key];   // no problem, foo is mutable
[bar setValue:value forKey:key];   // crash

Итак, если у меня есть объект, который является NSDictionary или NSMutableDictionary, если не считать блок попытки (которого я бы предпочел избежать), как я могу определить разницу?

Ответы [ 6 ]

5 голосов
/ 11 февраля 2012

Честно говоря, вы не можете легко определить разницу без блока @try. Стандартная практика выглядит следующим образом:

  • Если вы хотите проверить, является ли он изменчивым, чтобы не допустить, чтобы кто-то передавал вам неожиданно изменяемый объект, а затем изменял его из-под вас, copy словарь. Если он действительно не изменяемый, фреймворки оптимизируют это до retain. Если он действительно был изменяемым, то, возможно, вам все равно нужна копия.
  • Если вам нужен изменяемый словарь, объявите параметры вашего метода, чтобы он требовался. Все просто.
  • В общем, верьте, что люди не будут пытаться видоизменять объекты, если не указано, что они изменяемы.
3 голосов
/ 11 февраля 2012
NSAssert([bar isMemberOfClass: [NSMutableDictionary class]], @"");
1 голос
/ 11 февраля 2012

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

if ([bar isMemberOfClass:[NSMutableDictionary class]]){
    [bar setValue:value forKey: key];
}

Разница между SDK iPhone между isKindOfClass и isMemberOfClass

0 голосов
/ 15 августа 2014

Я использую @try catch, но он срабатывает только один раз. Так это работает так

NSMutableDictionary *valuesByIdMutable = (id)self.valuesById;

simplest_block block = ^{
    [valuesByIdMutable setObject:obj forKey:key];
};

@try {
    block();
} @catch (NSException *exception) {
    self.valuesById = valuesByIdMutable = [valuesByIdMutable mutableCopy];
    block();
}
0 голосов
/ 11 февраля 2012

Если вам действительно все равно, является ли он изменчивым, но все равно хотите его изменить, попробуйте следующее:

NSString* value = @"value";
NSString* key = @"key";

NSDictionary* bar = [NSDictionary dictionary];
NSLog(@"bar desc: %@", [bar description]);
NSMutableDictionary* temp = [bar mutableCopy];
[temp setValue:value forKey:key];
bar = temp;
NSLog(@"bar desc: %@", [bar description]);
0 голосов
/ 11 февраля 2012

Если вам нужно гарантировать, что словарь изменчив, вы должны:

  • создайте его как изменяемый, если вы тот, кто его инициализирует
  • превратите его в изменчивый экземпляр с помощью метода - [NSDictionary mutableCopy], например, если вы вызываете API, который возвращает NSDictionary. Обратите внимание, что mutableCopy увеличивает счетчик сохранения; вам нужно освободить этот экземпляр, если вы используете ручной подсчет ссылок.

Определение того, является ли NSDictionary изменчивым, прежде чем пытаться изменить его ключи и / или значения, можно считать примером запаха кода , указывающего, что существует более глубокая проблема, которую необходимо решить. Другими словами, вы всегда должны знать, является ли данный экземпляр словаря NSDictionary или NSMutableDictionary. Код должен быть ясен по этому вопросу.

...