objective-cnsmutabledictionarymutability

NSMutableDictionary and mutableCopy


I'm confused by the code, below. Before I added the mutableCopy line, it didn't work. After I added the line, it did.

Why isn't aDict mutable to begin with? I declared aDict as an NSMutableDictionary.

- (void) myRoutine: (NSMutableDictionary *) dictOfDicts
   {
   NSMutableDictionary * aDict = dictOfDicts[dictOfDictsKey];
   int                   data  = [aDict[aDictKey] intValue];

   aDict           = [aDict mutableCopy];
   aDict[aDictKey] = @(++data);
   }

Solution

  • The declaration of dictOfDicts says it's a pointer to a mutable dictionary. However, it does not use Objective-C generics syntax to say what the types of the keys or values are. So, the most we (and the compiler) can assume is that the keys are id<NSCopying> and the values are id, completely generic object pointers.

    You then initialize your aDict variable with a value obtained from dictOfDicts. You've declared that aDict is also a pointer to a mutable dictionary. That's its "static type", but the real type of the object it points to is determined at runtime by whatever object is held in dictOfDicts under that key. It might be a mutable dictionary or it might be something else. It compiles just find because the compiler can't know what type of object that value is.

    However, the real type (a.k.a. "dynamic type") of the object governs what operations succeed or fail/crash/whatever. In your case, it sounds like it's an immutable dictionary. So, when you attempt to mutate it, "it didn't work" (you don't specify what actually happened).

    You make a mutable copy and you're allowed to mutate that. However, that's now a separate object that the one in dictOfDicts. So, you're not modifying what you think you are.

    The solution is to put mutable dictionaries into dictOfDicts in the first place. Or, even better, put objects of a custom class of your own design into it, and operate on real properties.