在后台变异函数中保存struct

时间:2017-03-09 16:50:40

标签: swift cocoa-touch

我试图在后台保存一个结构但是我收到了这个错误:

  

闭包不能隐式捕获变异的自身参数

这是我的代码:

//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)
    }
}

我已检查过这些问题:1 - 2我已添加@escaping  但是没有工作。

1 个答案:

答案 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。)