我正在Swift中编写一个iOS应用程序,并且在结构和块方面存在一些问题。当用户编辑他的教育信息并单击保存按钮时,我向服务器发送请求并更新成功处理程序中的本地数据。在这里,我在课程editItem()
中编写了EditController
函数,在类editEducation()
结构中编写了UserModel
:
class EditController: UITableViewController {
//...
func editItem<T>(item: T, completion: () -> Void) {
switch selectedType {
case .Education:
let educationItem = item as! EducationModel
// self.user is a object of type "UserModel"
user!.editEducation(index: selectedRow, educationItem: educationItem) {
// breakpoint 2 here
completion()
self.tableView.reloadData()
}
default:
return
}
}
//...
}
struct UserModel {
//...
var education = [EducationModel]()
//EducationModel is also a structure
//...
mutating func editEducation(#index: Int, educationItem: EducationModel, completion: () -> Void) {
let manager = HTTPClient.sharedManager
manager.POST("/user/education/update",
parameters: [
// params
],
success: { (task, responseObject) in
if responseObject["status"] as! Int == 0 {
self.education[index] = educationItem
// breakpoint 1 here
completion()
} else {
println(responseObject)
}
},
failure: { (task, error) in
println(error)
}
)
}
//...
}
问题是,尽管在程序到达断点1时已成功更新self.education
(如上所述),self.user.education
仍然包含断点2处的旧数据。如果我移动
self.education[index] = educationItem
在POST请求之外,数据在断点2处按预期更新。我尝试通过在断点2处添加调度来延迟,但它仍然不会更新。我还打印了相关变量的内存地址,但它没有提供有用的信息。我现在通过向controller
添加editEducation
参数来处理此问题,在self
中传递EditController
并强制更新控制器的user
属性。我认为这不是一个合适的解决方案。那么有更好的方法吗?
更新1
我尝试将UserModel变成一个类并且它解决了这个问题,但是我不想这样做,因为:首先,如果我把它作为一个类,那么应用程序的其他部分的某些行为可能会变得奇怪将其他数十个模型转化为类以确保一致性。
答案 0 :(得分:5)
您在这里看到的是值类型(struct)和引用类型(class)之间的区别。您应该阅读Apple网站上关于差异的博文:https://developer.apple.com/swift/blog/?id=10
基本上,一旦你将一个struct传递给一个块,它就会被复制而不是被引用,所以你正在开发一个全新的副本。通过课程,您可以获得原始副本的参考。