在后台线程中自变异 Swift 结构

Self-mutate Swift struct in background thread

假设我们有一个能够自我突变的结构,它必须作为后台操作的一部分发生:

struct Thing {
    var something = 0
    mutating func operation(block: () -> Void) {            

        // Start some background operation
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {

            // Mutate self upon background task completion
            self.something += 1
            block()

        }

    }
}

现在,当我在上下文中使用这样的结构时:

var myThing = Thing()
myThing.operation {
    println(myThing.something)
}

println 给了我 0,就好像 myThing 从未发生过变异一样。从 dispatch_async 中打印 self.something 显然会产生 1.

我该如何解决这个问题,最好是不必在 operation 竞争块中传递更新的结构 self 并覆盖主上下文中的原始变量?

// Ew
var myThing = Thing()
myThing.operation {
    (mutatedThing) in
    myThing = mutatedThing
    println(myThing.something)
}

我已经多次看到这个确切的问题,但没有更多细节,我不能说它是否出于与您遇到它相同的原因而发生。

这让我发疯,直到我意识到分派的操作发生在不合逻辑的时间,即通常 当前时间之前。在调度块的参考框架中,它正确更新了变量,这就是它从块内部正确打印出来的原因。但是在"real world"中,由于某种原因,dispatch被认为从未发生过,值的变化被丢弃了。或者可能是因为突变隐式地创建了一个新结构并且因为它是 "time travelling" 对它的引用从未更新过。不能说。

就我而言,一旦我正确安排了发货时间,问题就消失了。希望对您有所帮助!

我正在添加第二个答案,因为我的第一个答案解决了不同的问题。

我自己也遇到了这个困难,情况和你几乎一模一样。

在努力找出发生了什么并修复它之后,我意识到问题基本上是在应该使用引用类型的地方使用了值类型。

闭包似乎创建了结构的副本并对其进行操作,而原始结构保持不变——这更符合值类型的行为。

另一方面,期望的行为是闭包中执行的操作由闭包外部的环境保留——换句话说,需要引用两个不同的上下文(闭包内部和外部)到相同的对象——这更符合引用类型的行为。

长话短说,我将结构更改为 class。问题消失了,不需要其他代码。