swift - 在后台变异函数中保存结构

标签 swift cocoa-touch

我正在尝试在后台保存一个结构,但出现此错误:

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

我已经检查了这些问题:1 - 2我添加了 @escaping 但没有用。

最佳答案

我认为,如果我们尽可能少地引出您收到的错误消息,将会有所帮助。 (对于 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/

相关文章:

ios - 如何在 Swift 中创建一个空的 SKSpriteNode?

ios - 使用 PromiseKit 处理错误

iphone - 用户单击另一个选项卡后如何删除 UITabBar 徽章?

iphone - iOS 在两个 Controller 之间切换

iphone - 通过循环将 TouchUpInside 事件分配给多个 UIImageView,并使用可以进一步对每个 UIImageView 进行动画/操作的处理程序方法

iphone - UIView的addSubview真的保留了view吗?

swift - 寻找一种更好的方法来区分 2 个数组

ios - Realm swift : instance member cannot be used on type

swift - iOS WatchOS5 - 如何以编程方式检测 Apple Watch 是否在特定时间间隔戴在手腕上?

objective-c - 使图像移动更多 "fluidly"