Swift:设置数组的一个值会同时更改其他值

时间:2016-05-04 16:47:31

标签: ios arrays swift data-structures

这就是我设置数据结构的方式:

class Commit: NSObject, NSCoding {

//MARK: Properties
var contents : String
var repeatStatus : Bool
var completionStatus : Bool

//MARK: Initialization
init(contents: String, repeatStatus: Bool, completionStatus: Bool) {

    self.contents = contents
    self.repeatStatus = repeatStatus
    self.completionStatus = completionStatus

    super.init()

}

//MARK: NSCoding
func encodeWithCoder(aCoder: NSCoder){
    aCoder.encodeObject(contents, forKey: PropertyKey.contentsKey)
    aCoder.encodeObject(repeatStatus, forKey: PropertyKey.repeatStatusKey)
    aCoder.encodeObject(completionStatus, forKey: PropertyKey.completionStatusKey)

}

required convenience init?(coder aDecoder: NSCoder) {

    let contents = aDecoder.decodeObjectForKey(PropertyKey.contentsKey) as! String
    let repeatStatus = aDecoder.decodeObjectForKey(PropertyKey.repeatStatusKey) as! Bool
    let completionStatus = aDecoder.decodeObjectForKey(PropertyKey.completionStatusKey) as! Bool

    self.init(contents: contents, repeatStatus: repeatStatus, completionStatus: completionStatus)
}

}

class ToDoList: NSObject, NSCoding {

//MARK: Properties
var commitArray : [Commit]
var date : Int

// MARK: Archiving Paths

static let DocumentsDirectory = NSFileManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
static let ArchiveURL = DocumentsDirectory.URLByAppendingPathComponent("toDoList")

//MARK: Initialization
override init(){

    let defaultCommit = Commit(contents: "", repeatStatus: false, completionStatus: false)
    self.date = dateTodayAsInt
    self.commitArray = [defaultCommit, defaultCommit, defaultCommit]

    super.init()
}

init(commitArray: [Commit], date: Int) {

    self.date = date
    self.commitArray = commitArray

    super.init()

}

//MARK: NSCoding
func encodeWithCoder(aCoder: NSCoder){

    aCoder.encodeObject(commitArray, forKey: PropertyKey.commitArrayKey)
    aCoder.encodeObject(date, forKey: PropertyKey.dateKey)

}

required convenience init?(coder aDecoder: NSCoder) {

    let commitArray = aDecoder.decodeObjectForKey(PropertyKey.commitArrayKey) as! [Commit]
    let date = aDecoder.decodeObjectForKey(PropertyKey.dateKey) as! Int

    self.init(commitArray: commitArray, date: date)
}


}

func findIndexOfActiveToDoList(allToDoLists: [ToDoList]) -> Int {

var j = Int(floor(Double((allToDoLists.count/2))))
var count = 0

repeat {
    count += 1

    if allToDoLists[j].date < dateTodayAsInt {
        j = Int(j + j/2)
    } else if allToDoLists[j].date > dateTodayAsInt {
        j = Int(j - j/2)
    } else { return j }

} while count < Int(sqrt(Double(allToDoLists.count/2)))

print(j)
return j }


// MARK: Types

struct PropertyKey {

static let contentsKey = "contents"
static let repeatStatusKey = "repeatStatus"
static let completionStatusKey = "completionStatus"

static let commitArrayKey = "commitArray"
static let dateKey = "date"

}

var toDoList = [Commit]()
var allToDoLists = [ToDoList]()

稍后,当我想更新allToDoLists数组时,如下所示:

FirstCommitTextField.text! = allToDoLists[findIndexOfActiveToDoList(allToDoLists)].commitArray[0].contents

无论我做什么,只要我设置:

SecondCommitTextField.text! = allToDoLists[findIndexOfActiveToDoList(allToDoLists)].commitArray[1].contents

提交数组的第一个元素的content属性也会更改。我已经运行应用程序,打印注释在设置提交数组的第二个元素的内容属性之前和之后打印提交数组的第一个元素的内容属性 - 只是设置第二个属性以某种方式更改了第一个元素。

这使我得出结论,以某种方式设置数组中元素的值也会改变该数组中第二个元素的值。是这样的吗?如果是,如何避免/规避这一点?

提前致谢!

1 个答案:

答案 0 :(得分:0)

我怀疑你打算写:

allToDoLists[findIndexOfActiveToDoList(allToDoLists)].commitArray[0].contents = 
    FirstCommitTextField.text!
allToDoLists[findIndexOfActiveToDoList(allToDoLists)].commitArray[1].contents = 
    SecondCommitTextField.text!

如果是这种情况,那么您看到第二次更新会影响commitArray[0]内容的原因是您初始化了ToDoList.commitArray

self.commitArray = [defaultCommit, defaultCommit, defaultCommit]

你的Commit是一个常规类而不是struct,所以它是通过引用传递的(参见:structure vs class in swift language)。因此,当您更改commitArray[0].contents时,您会在commitArray[1].contentscommitArray[2].contents中看到相同的值。

请注意,对象引用由NSCoder保留,因此如果它们在序列化之前是同一个对象,则在反序列化后它们将是相同的。

解决方案

您应该使用默认参数初始化新实例,而不是重新使用let defaultCommit = Commit(...)。例如,为Commit添加便利初始值设定项:

convenience override init() {
    self.init(contents: "", repeatStatus: false, completionStatus: false)
}

override是必需的,因为NSObject已经声明了无参数init。)

然后使用它:

self.commitArray = [Commit(), Commit(), Commit()]