iOS – distinguer un NSDictionary d'un NSMutableDictionary?

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:

  • Si vous voulez vérifier si elle est mutable afin d'éviter que quelqu'un ne vous passe un object mutable de manière inattendue et le transforme ensuite en dessous de vous, 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.
  • Si vous avez besoin d'un dictionary mutable, déclarez vos parameters de méthode pour en exiger un. Aussi simple que cela.
  • En général, faites confiance au fait que les gens n'essaieront pas de muter des objects à less qu'ils ne disent spécifiquement qu'ils sont mutables.

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:

  • le créer comme mutable si vous êtes celui qui l'initialise
  • transformez-la en une instance mutable avec la méthode – [NSDictionary mutableCopy], par exemple si vous appelez une API qui returnne un NSDictionary. Notez que mutableCopy incrémente le nombre de retenues; vous devez libérer cette instance si vous utilisez le comptage manuel des references.

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(); }