Sami
Sami

Reputation: 587

Why does the value in this dictionary change?

I've been trying to debug something in my code and came across this. You can put this directly in playground.

import UIKit

class testObj {
    var prop1: Int?
}

var testObjInst = testObj()

var myDic : [String : testObj] = [:]

testObjInst.prop1 = 1
myDic["A"] = testObjInst
testObjInst.prop1 = 2
myDic["B"] = testObjInst
testObjInst.prop1 = 3
myDic["C"] = testObjInst

print(myDic["A"]?.prop1) //prints 3

if let myVal = myDic["A"] {
    myVal.prop1 = 5
}

print(myDic["A"]?.prop1) //prints 5

How is the myVal variable changing the value for myDic["A"]? Shouldn't myVal be assigned to the result of calling myDic["A"] and the return of this call would ultimately be a new instance of the object?

Edit 1: My segues are performed like this:

    if segue.identifier == segueIDs.air {
        if let vc = segue.destination as? PointsTableViewController {
            //these are the dictionaries. 
            vc.rewardProgramsDic = rewardProgramsDic
        }
    }

The issue I've been getting is when a property was set in the destination viewController, when I would press back and print the values in the rewardProgramsDic the values would have changed. I tried setting breakpoints on the rewardProgramsDic as well as using didSet to try and catch the change but neither of those is called when a property is updated in the destination viewController.

Edit 2:

In the originating viewController:

var rewardProgramsDic: [String: IndividualRewardProgram] = [:]

In the destination tableViewController

var rewardProgramsDic:  [String: IndividualRewardProgram] = [:] 

Upvotes: 2

Views: 89

Answers (2)

Sami
Sami

Reputation: 587

Using this function:

func address<T: AnyObject>(o: T) -> Int {
    return unsafeBitCast(o, to: Int.self)
}

and calling it the parent view controller, like this:

print(NSString(format: "%p", address(o: rewardProgramsDic["ID1"]!))) 

and then calling this same function in the destination view controller, I confirmed that the parent view controller and the destination view controller's variables were pointing to the same place in memory. This explains why I was getting the cascading down change explained with my conversation with @Nirav.

Thank you both for your responses.

Upvotes: 0

Sagar Thummar
Sagar Thummar

Reputation: 2124

Here, you are getting such result because you are using Class.

Class is reference types & reference types are not copied when they are assigned to a variable or constant, or when they are passed to a function.

Mean by updating object value, will updates all the instances where they actual assigned. Here in above example,

testObjInst.prop1 = 1
myDic["A"] = testObjInst // myDic["A"]?.prop1 :- 1
testObjInst.prop1 = 2
myDic["B"] = testObjInst // myDic["B"]?.prop1 :- 2 & myDic["A"]?.prop1 :- 2
testObjInst.prop1 = 3
myDic["C"] = testObjInst // myDic["C"]?.prop1 :- 3 & myDic["B"]?.prop1 :- 3 & myDic["A"]?.prop1 :- 3

if let myVal = myDic["A"] { //So Here, myDic["A"]?.prop1 :- 3
    //Here, myDic["A"] class instance is assigned to myVal object, 
    //So changing value in myVal object directly reflect in all object.
    myVal.prop1 = 5 // myDic["A"]?.prop1 :- 5 & myDic["B"]?.prop1 :- 5 & myDic["C"]?.prop1 :- 5
}

Upvotes: 1

Related Questions