0

I am having an issue with two dictionaries. In my header file I declare a dictionary:

@property (strong, nonatomic) NSMutableDictionary *templateDictionary

The templateDictionary holds strings and dictionaries, such as 'blankCopy', which in turn holds other strings and dictionaries. I am also declaring a dictionary within my implementation file:

@property (strong, nonatomic) NSMutableDictionary *exampleDictionary

In my implementation I am trying to set part of the exampleDictionary to a portion of the templateDictionary like so:

[self.exampleDictionary setObject:[templateDictionary objectForKey:@"blankCopy"] forKey:@"template"];

This works until I change anything within exampleDictionary's 'template'. Now when I go back to the templateDictionary it has also changed. I figured this was because it was pointing back. I have tried the following but all don't have any effect:

[self.exampleDictionary setObject:[[templateDictionary objectForKey:@"blankCopy"] copy] forKey:@"template"];
[self.exampleDictionary setObject:[[templateDictionary objectForKey:@"blankCopy"] mutableCopy] forKey:@"template"];
[self.exampleDictionary setObject:[NSMutableDictionary dictionaryWithDictionary:[templateDictionary objectForKey:@"blankCopy"]] forKey:@"template"];

Any ideas as to what's wrong and how to fix it, or how to copy a dictionary object by values?

dgee4
  • 381
  • 3
  • 16
  • I guess you set the `self.exampleDictionary` in a method that gets called always when the view is re-opened. (viewwillappear or something ) maybe you should check if the dictionary is empty before setting it. – LoVo May 26 '15 at 17:18
  • @LoVo I set the exampleDictionary when ever I need a fresh template i.e. A version of 'blankCopy', except updating exampleDictionary always ends up with 'blankCopy' not being blank! – dgee4 May 26 '15 at 17:20
  • What is the dataType of object for `[templateDictionary objectForKey:@"blankCopy"]` ? – iphonic May 26 '15 at 17:20
  • @iphonic it's a dictionary created by JSON Serialisation – dgee4 May 26 '15 at 17:26
  • A dictionary contains **POINTERS**. If you copy the pointers from one dictionary to another, you do not create copies of the objects pointed to. – Hot Licks May 26 '15 at 17:31

2 Answers2

2

The problem here is that a dictionary only keeps references to the contained objects. When you copy a dictionary, you are only copying the reference, not the objects. So, if you modify something inside one dictionary, you'll see it modified in the other.

The solution would be to deep-copy the contents of the dictionary, that is, for each object stored in the dictionary, if it is also a dictionary, deep-copy it and store in the new dictionary.

You can look for example at this answer, which has the implementation.

Community
  • 1
  • 1
Marcos Crispino
  • 8,018
  • 5
  • 41
  • 59
1

First, an aside: you don't need to do this:

[self.exampleDictionary setObject:[templateDictionary objectForKey:@"blankCopy"] forKey:@"template"];

This is much easier to read:

self.exampleDictionary[@"template"] = templateDictionary[@"blankCopy"];

You will see old code written like the first line, but for new code the second line is far preferable. That syntax has worked in Xcode for at least two years now.

The real problem you have is that [NSMutableDictionary mutableCopy] is only a shallow copy -- it's a new dictionary, but the values in the dictionary are referenced, not copied. You need a deep copy. Check out http://samwize.com/2014/05/12/deep-copying-of-nsarray-slash-nsdictionary-slash-any-object/ for an approach using NSKeyedUnarchiver or https://gist.github.com/yfujiki/1664847 for a direct (but more verbose) approach.

Ewan Mellor
  • 6,747
  • 1
  • 24
  • 39