Change Inside For Loop in Swift Object Properties

I created a simple structure 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 an array of ShoppingList as follows:

  var shoppingLists = [ShoppingList]() 

After that, I take shopping lists, etc. Now I repeat the shopping lists and change the title, but it will ever update 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 run the loop, it copies by value and therefore the original array never changes. How to change the original array using a For loop?

+5
source share
2 answers

There are two approaches that I would use here. The first approach is to reconsider whether ShoppingList a value type or a reference type. The fact that it has an identifier tells me that it is indeed a reference type. If two shopping lists have the same content, should the same list be read? I suspect not. What does it mean to have two lists with the same identifier but with different content? If this is illegal, again, this indicates that it is a reference type because it has an identifier.

If it is a reference type, make it final class :

 final class ShoppingList {} 

Final classes keep structures simple because they do not suffer from inheritance problems. But they give referential semantics. With this change, your source code will work.

Another way to approach this is a more functional one, where everything is value. In this case, you can achieve this by copying copies of your shopping lists:

 shoppingLists = shoppingLists.map { list in var newList = list newList.groceryItems = getGroceryItemsByShoppingList(list) return newList } 

This pushes us to a more functional approach, but makes this identifier inconvenient. Therefore, if you really wanted to go this route, I would like to get rid of identifiers and, possibly, even make shopping lists unchanged. In this case, any two identical shopping lists are the same list, and you can write in a more functional style.

But I suspect that creating a ReferenceList ShoppingList is your best approach.

+8
source

Ok, I figured it out. It seems that now you do this by creating a link and changing its properties inside the loop (which does not change the original instance in the case of structures). Instead, you should call them as follows:

 for index in 0..<shoppingLists.count { //Stuff you do. Do the same way, just replace "shoppingList" to "shoppingLists[index]" shoppingLists[index].title = "BLAH" // copied by value print("ShoppingList \(shoppingLists[index].title) has items") // THIS PRINT BLAH } print("shoppingLists[0].groceryItems.title: \(shoppingLists[0].title)") // Returns "shoppingLists[0].groceryItems.title: BLAH" 

It works, I checked, please!

+2
source

Source: https://habr.com/ru/post/1238403/


All Articles