J'ai le fragment de code suivant:
NSSsortingng* value = @"value"; NSSsortingng* 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
Donc, si j'ai un object qui est soit un NSDictionary
ou un NSMutableDictionary
, à court d'un bloc try (que je préfère éviter), comment puis-je faire la différence?
NSAssert([bar isMemberOfClass: [NSMutableDictionary class]], @"");
Honnêtement, vous ne pouvez pas facilement faire la différence sans un bloc @try
. La pratique standard est la suivante:
copy
le dictionary. Si c'est vraiment non-mutable, les frameworks l'optimiseront dans une retain
. Si c'était vraiment mutable, alors vous en vouliez probablement une copy quand même. C'est assez simple en fait, tout ce que vous devez faire est de tester contre le membre de la class, comme ceci:
if ([bar isMemberOfClass:[NSMutableDictionary class]]){ [bar setValue:value forKey: key]; }
Différence du SDK iPhone entre isKindOfClass et isMemberOfClass
Si vous devez garantir qu'un dictionary est modifiable, vous devez:
Déterminer si un NSDictionary est mutable avant d'essayer de modifier ses keys et / ou ses valeurs peut être considéré comme un exemple d' odeur de code , indiquant qu'il existe un problème plus profond qui devrait être résolu. En d'autres termes, vous devez toujours savoir si une instance de dictionary donnée est NSDictionary ou NSMutableDictionary. Le code devrait être clair sur ce point.
Si vous vous en fichez vraiment, mais que vous voulez le faire muter, vous pouvez essayer ceci:
NSSsortingng* value = @"value"; NSSsortingng* 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]);
Je finis par utiliser @try catch mais il ne se triggers qu'une fois. Donc ça marche comme ça
NSMutableDictionary *valuesByIdMutable = (id)self.valuesById; simplest_block block = ^{ [valuesByIdMutable setObject:obj forKey:key]; }; @try { block(); } @catch (NSException *exception) { self.valuesById = valuesByIdMutable = [valuesByIdMutable mutableCopy]; block(); }