I created a simple struct called ShoppingList.
struct ShoppingList {
var shoppingListId :NSNumber
var title :String
var groceryItems :[GroceryItem]
init() {
self.title = ""
self.groceryItems = [GroceryItem]()
self.shoppingListId = NSNumber(integer: 0)
}
}
Next I created a ShoppingList array like this:
var shoppingLists = [ShoppingList]()
After that I fetch the shopping lists etc. Now, I iterate through the shoppingLists and change the title but it ever updates the title property.
for var shoppingList in shoppingLists {
let items = getGroceryItemsByShoppingList(shoppingList)
shoppingList.groceryItems = getGroceryItemsByShoppingList(shoppingList)
shoppingList.title = "BLAH" // copied by value
print("ShoppingList \(shoppingList.title) has \(shoppingList.groceryItems.count) items") // THIS PRINT BLAH
}
print("shoppingLists[0].groceryItems.count \(shoppingLists[0].groceryItems.count)") // THIS PRINTS THE ORIGINAL CONTENT
I believe that when I am running the loop it is copying by value and hence the original array is never changed. How can I change the original array using For loop?
There are two approaches I would use here. The first approach is to reconsider whether ShoppingList
is a value type or a reference type. The fact that it has an identifier suggests to me that it's really a reference type. If two shopping lists have the same contents, should the be considered the same list? I suspect not. What would it mean to have two lists that have the same identifier, but different contents? If that's illegal, again, that tends to point to it being a reference type because it has an identity.
If it's a reference type, make it a final class
:
final class ShoppingList {}
Final classes preserve the simplicity of structs because they do not suffer the problems of inheritance. But they provide reference semantics. With that change, your original code would work.
The other way to approach this is more functional, where everything is a value. In that case, you can achieve this by mapping copies of your shopping lists:
shoppingLists = shoppingLists.map { list in
var newList = list
newList.groceryItems = getGroceryItemsByShoppingList(list)
return newList
}
This pushes us towards a more functional approach, but it makes the identifier awkward. So if you really wanted to go this way, I'd want to get rid of identifiers and maybe even make shopping lists immutable. In that case, any two identical shopping lists are the same list, and you can write in a more functional style.
But I suspect that making ShoppingList
a reference type is your better approach.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With