Search code examples
iosswiftclassdictionaryfoundation

How to prevent from modifying a copy of dictionary


I've got a following problem.

I have a function called A which takes a following dictionary as an argument [String : MyClass], where MyClass is a custom class that I've created (it's a subclass of NSObject). MyClass has a property called firstProperty.

Function A looks like so:

func A (someDictionary : [String : MyClass]) {
    var someDictionaryCopy = someDictionary

    someDictionaryCopy["Key"].updateValue()
} 

Ok, so the first line in the body of the function A is copying the someDictionary that is passed to the function A. But I DON'T want to mutate or modify the original someDictionary.

The second line: I take some existing value in the dictionary and run a method on MyClass instance which modifies one of its properties.

The thing is that if I run the code above, the original dictionary that's passed to the function is modified as well? Why is it so? How can I pass a dictionary to the function so that it's not mutated?

For your convenience, here's a sample of MyClass implementation:

class MyClass : NSObject {
    var someProperty : Double = 0.0

    func updateValue() {
        someProperty += 10.0
    }
}

Solution

  • The issue is that MyClass is a reference type. When you copy the dictionary, it does, truly, make a new copy of the dictionary, but the new copy has references to the same instances of MyClass that the original dictionary has. Changes made to a copy of a reference to an instance of MyClass anywhere, whether it is inside a dictionary or any other value type, will be reflected in any other reference to that same instance of MyClass.

    Basically, the dictionary is a value type, which means it has value semantics. But the values in the dictionary are reference types, so they have reference semantics. The only way around this is to create a dictionary with new instances of MyClass for every key in the dictionary. Or, as @EricD suggested, use structs instead of classes to get the value semantics that you want.