Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/facebook/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 数组的副本正在更改原始数组_Arrays_Swift - Fatal编程技术网

Arrays 数组的副本正在更改原始数组

Arrays 数组的副本正在更改原始数组,arrays,swift,Arrays,Swift,我有两个控制器。第一个控制器从服务器加载一个列表,并创建一个自定义对象列表,WordList class WordList { let name: String let releaseDate: Date var words: [String] let multiplier: Int ... } 在第一个屏幕上,用户可以在继续之前选择列表。在下一个控制器上,从随机列表中选择一个随机字。单词出现后,在用户与其交互时将其删除。一旦用户不进行交互,就会选择

我有两个控制器。第一个控制器从服务器加载一个列表,并创建一个自定义对象列表,
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
引用从第一个数组复制到第二个数组中。总之,问题不在于
数组
,它是一种值类型,而在于
单词列表
,它是一种引用类型

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

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

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

  • 如果确实需要使用
    ,请编写自己的
    copy
    方法返回新实例。例如,您可以遵循
    NSCopying
    并编写
    副本(使用:)

    然后,在构建新阵列时,将副本而不是引用附加到原始实例:

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

如果您不喜欢
NSCopying
copy
引入了笨拙的
Any
返回类型,您也可以定义您的
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())
}
你说:

我明白我必须传递列表的引用,而不是实际复制它

不,您正在传递一个新数组

。。。但我不认为如果我通过复制第一个数组中的值来填充第二个数组,它会是这样工作的

不幸的是,您没有从第一个数组“复制值”,而是将
WordList
引用从第一个数组复制到第二个数组中。总之,问题不在于
数组
,它是一种值类型,而在于
单词列表
,它是一种引用类型

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

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

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

  • 如果确实需要使用
    ,请编写自己的
    copy
    方法返回新实例。例如,您可以遵循
    NSCopying
    并编写
    副本(使用:)

    然后,在构建新阵列时,将副本而不是引用附加到原始实例:

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

如果您不喜欢
NSCopying
copy
引入了笨拙的
Any
返回类型,您也可以定义您的
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())
}

我会避免nscopy,因为该协议的唯一要点是支持NSObject.copy。它还引入了任何不需要的类型。
NSCopying
协议没有只针对
NSObject
子类的要求(例如,如果它真的只针对
NSObject
,它将有
NSObjectProtocol
要求)。但是我承认,我发现
NSCopying
任何
返回类型的使用有点不简洁。您始终可以定义自己的
复制协议。我只是讨厌引入另一个很大程度上重复的协议/方法,而现有的协议就是为了这个目的而设计的。实际上不需要复制协议。协议存在的唯一原因是
NSObject
有一个
copy
方法,当实例不符合
NSCopying
时抛出异常,否则调用
copy(withZone:)
。最初的原因可能是需要
copy
属性,但在Swift中,我只声明一个复制构造函数(initalizer)。我同意您不需要协议(因此我的评论是您“可以定义
copy
方法”),但这似乎是最佳实践,IMHO,为这些常见的抽象模式定义协议。它在国际文传电讯组织中明确了意图