简体   繁体   中英

Struct Gobal is being updated from another VC when it shouldn't be

We are creating a global struct where we store our products for a shopping cart. Here is the code to create it

class Cart : NSObject {
    var allProductsInCart = [Product]()

    class var sharedCart: Cart {
        struct Static {
            static let instance = Cart()
        }
        return Static.instance
    }
}

In a separate view controller (called ProductVC), we are creating an instance of Product. We add that product to the array listed above, allProductsInCart like this and then change the value:

let newProduct = Product()
newProduct.name = "Costco"
Cart.sharedCart.allProductsInCart.append(newProduct)
newProduct.name = "test2"
print ("value is: \(Cart.sharedCart.allProductsInCart[0].name)") //It prints "test2" not "Costco" 

When the separate instance of product is modified in ProductVC, it is also changed in the struct. It is definitely a separate instance of product because it has a different variable name as seen above.

It should print Costco still because the instance of Product within the ProductVC was modified after it was added to the struct and we want to print the instance in the struct. Right? Or do I have something wrong?

Is this normal behavior? Is there a reason this is happening? Is there a better way that a global variable is supposed to be created or a better way to create a sharedCart that we can access in any view controller?

This happens because newProduct is a reference type (defined by a class) so when you change the name it just changes the name of the same reference. There is only one product in the cart at this point, not two. For reference, the easiest way to define a singleton in Swift would be

class Cart {
    static let shared = Cart()

    var products = [Product]()
}

So, just following your example:

let newProduct1 = Product()
newProduct1.name = "Costco"

Cart.sharedCart.products.append(newProduct1)

let newProduct2 = Product()  // a new product
newProduct2.name = "test2"
// I assume you will want to add this product as well
Cart.shared.products.append(newProduct2)

//This will print "Costco" 
print ("value is: \(Cart.sharedCart.products[0].name)") 

The reason why allProductsInCart is returning a different value is because of a concept known as Pass by Value versus Pass by Reference , it is nothing to do with the variable being static, or global.

Product is an object. All objects are known as Pass by Reference . This means that the value of the object points to a location in memory, and whenever that value at that location in memory is changed, then, the value is changed everywhere else pointing to that location in memory.

As allProductsInCart stores an array of Product , then it is storing an array of Objects , which means, whenever you change the value of the object, you are changing the value of wherever it is stored in memory.

Edit: If you wanted it to be pass by value , you would have to convert your array to a primitive data type. For example:

var productName = [String]() would prevent the value from being changed.

Your code would then look like:

class Cart : NSObject {
    var productName = [String]()
    static let instance = Cart()
}

Then when you call

let newProduct = Product()
newProduct.name = "Costco"
Cart.instance.productName.append(newProduct.name!)
newProduct.name = "test2"
print("Value is \(Cart.instance.productName[0])")

It will print Costco.

Look at What's the difference between passing by reference vs. passing by value? For further information about pass by value and pass by reference

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM