阵列的副本正在更改原始

时间:2018-11-26 14:53:15

标签: arrays swift

我有两个控制器。第一个控制器从服务器加载列表并创建自定义对象列表WordList

class WordList {

    let name: String
    let releaseDate: Date
    var words: [String]
    let multiplier: Int

    ...
}

在第一个屏幕上,用户可以选择继续操作之前的列表。在下一个控制器上,从随机列表中选择一个随机词。出现单词后,在用户与之交互时将其删除。一旦用户不进行交互,就选择一个新单词,直到没有更多单词为止。如果我回到主控制器并选择我刚才使用过的相同列表,则该列表将为空。这就是我发送所选项目的方式。

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let destination = segue.destination as? WordController {
        var wordLists = [WordList]()

        for index in tableView.indexPathsForSelectedRows! {
            wordLists.append(lists[index.row]) // lists is a class property that is a WordList array.
        }

        // This was my first attempt. Values were copied but removed from this controller.
        // for wordList in wordLists {
        //   destination.wordLists.append(wordList)
        // }

        // destination.wordLists = wordLists

        // This was my second attempt. Values were also copied but removed from this controller.
        destination.wordLists.append(contentsOf: wordLists)
    }
}

我知道我必须传递列表的引用,而不是实际复制它,但是我不认为如果我通过从第一个数组中复制值来填充第二个数组,那将是如何工作的。

除了每次用户返回屏幕时都重新加载第一个控制器外,我该如何进行这项工作,以便用户可以重用已清除的列表?

1 个答案:

答案 0 :(得分:4)

您说:

  

我知道我必须传递列表的引用,而不是实际复制它...

不,您要传递一个新数组。

  

...但是我不认为如果我通过复制第一个数组中的值来填充第二个数组,那将不会如此。

不幸的是,您不是从第一个数组“复制值”,而是从第一个数组复制WordList引用到第二个数组。归根结底,问题不在于值类型的Array,而是引用类型的WordList

WordList是引用类型,因为它是class。因此,当您从一个数组引用WordList并将其添加到另一个数组时,第二个数组仍将引用相同的WordList实例。

如果您不希望对其他阵列实例的操作影响原始实例,则可以:

  • WordList从引用类型(class)更改为值类型(struct):

    struct WordList {
        let name: String
        let releaseDate: Date
        var words: [String]
        let multiplier: Int
    }
    
  • 如果确实需要使用class,请编写自己的copy方法以返回新实例。例如,您可能符合NSCopying并编写了copy(with:)

    extension WordList: NSCopying {
        func copy(with zone: NSZone? = nil) -> Any {
            return WordList(name: name, releaseDate: releaseDate, words: words, multiplier: multiplier)
        }
    }
    

    ,然后在构建新数组时,附加副本而不是引用原始实例:

    for index in tableView.indexPathsForSelectedRows! {
        wordLists.append(lists[index.row].copy() as! WordList)
    }
    

如果您不喜欢NSCopyingAny引入笨拙的copy返回类型的事实,那么您也可以只定义copy方法甚至编写自己的Copying协议,例如:

protocol Copying {
    associatedtype ObjectType = Self
    func copy() -> ObjectType
}

extension WordList: Copying {
    func copy() -> WordList {
        return WordList(name: name, releaseDate: releaseDate, words: words, multiplier: multiplier)
    }
}

然后您可以执行以下操作而无需强制转换:

for index in tableView.indexPathsForSelectedRows! {
    wordLists.append(lists[index.row].copy())
}