Changing Object's Properties Inside For Loop in Swift

后端 未结 2 1927
无人共我
无人共我 2021-02-20 18:17

I created a simple struct called ShoppingList.

struct ShoppingList {

    var shoppingListId :NSNumber
    var title :String
    var groceryItems :[GroceryItem]         


        
相关标签:
2条回答
  • 2021-02-20 19:15

    Alright, I figured this out. It seems that the way you do this now is by making a reference and changing its properties inside of the loop (which does not change an original instance in case of structures). What you should do instead is call them directly like this:

    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"
    

    This works, I checked, you're welcome!

    0 讨论(0)
  • 2021-02-20 19:17

    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.

    0 讨论(0)
提交回复
热议问题