在Swift中更改For循环中的对象属性

时间:2015-12-16 16:53:25

标签: ios swift

我创建了一个名为ShoppingList的简单结构。

struct ShoppingList {

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

    init() {
        self.title = ""
        self.groceryItems = [GroceryItem]()
        self.shoppingListId = NSNumber(integer: 0)
    }

}

接下来,我创建了一个ShoppingList数组,如下所示:

 var shoppingLists = [ShoppingList]()

之后我获取购物清单等。现在,我遍历shoppingLists并更改标题,但它会更新title属性。

 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

我相信当我运行循环时,它是按值复制的,因此原始数组永远不会改变。如何使用For循环更改原始数组?

2 个答案:

答案 0 :(得分:8)

我会在这里使用两种方法。第一种方法是重新考虑ShoppingList是值类型还是引用类型。它有一个标识符这一事实告诉我它确实是一个引用类型。如果两个购物清单具有相同的内容,是否应该被视为相同的列表?我怀疑不是。拥有两个具有相同标识符但内容不同的列表意味着什么?如果那是非法的,那么它往往指向它是一种引用类型,因为它具有一个身份。

如果是引用类型,请将其设为final class

final class ShoppingList {}

最终类保留了结构的简单性,因为它们不会遇到继承问题。但它们提供了参考语义。通过该更改,您的原始代码将起作用。

另一种方法是更具功能性,一切都是价值。在这种情况下,您可以通过映射购物清单的副本来实现此目的:

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

这促使我们采用更具功能性的方法,但它使标识符变得尴尬。所以如果你真的想这样做,我想摆脱标识符,甚至可能使购物清单变得不可变。在这种情况下,任何两个相同的购物清单都是相同的列表,您可以用更实用的风格书写。

但我怀疑让ShoppingList作为参考类型是更好的方法。

答案 1 :(得分:2)

好吧,我想出来了。现在看来你现在这样做的方法是在循环中创建一个引用并改变它的属性(在结构的情况下不改变原始实例)。你应该做的是直接打电话给他们:

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"

这是有效的,我查了一下,欢迎您!