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

时间:2015-09-07 04:19:43

标签: multithreading swift struct mutators

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

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

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

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

2 个答案:

答案 0 :(得分:6)

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

我在与你几乎完全相同的情况下遇到了这种困难。

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

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

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

长话短说,我把结构改成了一个类。问题消失了,不需要其他代码。

答案 1 :(得分:0)

我已多次看到这个确切的问题,但没有更详细的说明,我不能说它是否因为你正在使用它而发生。

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

在我的情况下,一旦我正确安排了调度,问题就消失了。我希望有所帮助!