我试图在后台保存一个结构但是我收到了这个错误:
闭包不能隐式捕获变异的自身参数
这是我的代码:
//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)
}
}
答案 0 :(得分:4)
我认为如果我们最低限度地引出您收到的错误消息,这将有所帮助。 (对于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
是合法的;这就是mutating
的含义。但在这种情况下,我们提议离开一段时间,然后突然重新出现在现场(在这种情况下1秒后)和现在变异self
。因此,我们将保留self
的副本,直到将来某些不连贯的时刻,self
突然以某种方式被替换。这是不连贯的,尤其是因为谁知道原来的self
可能在此期间是如何变异的,使我们的副本不完美;并且编译器会阻止它。
非脱节闭包不会出现同样的问题:
func f(_ f:()->()) {}
struct S {
var name = ""
mutating func test() {
f {
self.name = "Matt" // fine
}
}
}
那是因为关闭是无关紧要的;它现在执行,所以不存在将来会发生什么的不一致性。这是转义和非转义闭包之间的重要区别,也是它们被区分的原因之一。
此外,同一个问题不会出现在课程中:
class C {
var name = ""
func test() {
delay(1) {
self.name = "Matt" // fine
}
}
}
这是因为类实例是由闭包中的引用捕获的,并且类实例是可变的就位。
(另见我的小文章:https://stackoverflow.com/a/27366050/341994。)