6

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

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从未变异过。self.something从内印dispatch_async量明显出来1

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

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

2 回答 2

6

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

我自己刚刚在与您的情况几乎相同的情况下遇到了这个困难。

在工作和工作并努力尝试找出发生了什么并修复它之后,我意识到问题基本上是在应该使用引用类型的情况下使用值类型。

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

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

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

于 2015-10-15T00:25:21.273 回答
0

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

这让我发疯,直到我意识到派遣的行动发生在一个不合逻辑的时间,即通常当前时间之前。在调度块的参考框架中,它正确地更新了变量,这就是它从块内部正确打印出来的原因。但是在“现实世界”中,由于某种原因,调度被认为从未发生过,并且丢弃了值的变化。或者可能是因为突变隐含地创建了一个新结构,并且因为它是“时间旅行”,所以对它的引用从未更新。不能说。

就我而言,一旦我正确安排了调度,问题就消失了。我希望这会有所帮助!

于 2015-09-22T17:24:34.210 回答