我有两个控制器。第一个控制器从服务器加载一个列表并创建一个自定义对象列表,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)
}
}
我知道我必须传递列表的引用,而不是实际复制它,但是我不认为如果我通过从第一个数组中复制值来填充第二个数组,那么它将如何工作。
除了每次用户返回屏幕时重新加载第一个控制器之外,我如何才能让用户重新使用已清除的列表?
最佳答案
你说:
我知道我必须传递列表的引用,而不是复制它…
不,您正在传递一个新数组。
…但我不认为如果我通过从第一个数组中复制值来填充第二个数组会是这样。
不幸的是,不是从第一个数组“复制值”,而是将WordList
引用从第一个数组复制到第二个数组。归根结底,问题不是值类型的Array
,而是引用类型的WordList
。WordList
是引用类型,因为它是一个class
。因此,当您从一个数组引用WordList
并将其添加到另一个数组时,第二个数组仍将引用相同的WordList
实例。
如果不希望对其他数组实例的操作影响原始实例,可以:
将WordList
从引用类型(aclass
)更改为值类型(astruct
):
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)
}
如果您不喜欢
NSCopying
为Any
引入尴尬的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())
}