我正在尝试在后台保存一个结构,但出现此错误:
closure cannot implicitly capture a mutating self parameter
这是我的代码:
//MARK: Parse self methods
fileprivate mutating func ParseSave(_ completionBlock: @escaping SuccessCompletionBlock) {
let message: PFObject = PFObject(className: "Message")
if let id = self.id {
//this object exit just update it
message.objectId = id
}
// set attributes
if let text = self.text {
message["text"] = text
}
message["sender"] = PFUser(withoutDataWithObjectId: self.sender.id)
message["conversation"] = PFObject(withoutDataWithClassName: "Conversation", objectId: conversationId)
message["viewed"] = self.viewed
message.saveInBackground { (success, error) in
if success {
// the next 3 lines cause the error : (when I try to update the struct - self )
self.id = message.objectId
self.createdAt = message.createdAt ?? self.createdAt
self.updatedAt = message.updatedAt ?? self.updatedAt
}
completionBlock(success, error)
}
}
最佳答案
我认为,如果我们尽可能少地引出您收到的错误消息,将会有所帮助。 (对于 delay
,请参阅 dispatch_after - GCD in swift?。)
struct S {
var name = ""
mutating func test() {
delay(1) {
self.name = "Matt" // Error: Closure cannot ...
// ... implicitly capture a mutating self parameter
}
}
}
原因在于结构(和枚举)突变的特殊性质:即,它并不真正存在。当你设置一个结构的属性时,你真正做的是复制结构实例并将其替换为另一个。这就是为什么只有 var
引用的结构实例可以被改变:为了使实例可变,引用必须是可替换的。
现在我们可以看到我们的代码出了什么问题。显然,mutating
方法改变 self
是合法的;这就是变异
的意思。但在这种情况下,我们提议离开一段时间,然后突然重新出现在场景中(在这种情况下,1 秒后)并现在变异self
。因此,我们将维护 self
的副本,直到将来某个断开连接的时刻,届时 self
将以某种方式突然被替换。这是不连贯的,尤其是因为谁知道原来的 self
可能在此期间发生了变异,从而使我们的副本变得不完美;编译器会阻止它。
非转义闭包不会出现同样的问题:
func f(_ f:()->()) {}
struct S {
var name = ""
mutating func test() {
f {
self.name = "Matt" // fine
}
}
}
那是因为闭包是非转义的;它是现在执行的,因此不存在关于 future 会发生什么的不连贯性。这是转义闭包和非转义闭包的一个重要区别,也是区分它们的原因之一。
另外,类不会出现同样的问题:
class C {
var name = ""
func test() {
delay(1) {
self.name = "Matt" // fine
}
}
}
那是因为类实例在闭包中被引用捕获,并且类实例就地是可变的。
(另请参阅我的小文章:https://stackoverflow.com/a/27366050/341994。)
关于swift - 在后台变异函数中保存结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42701005/