Self-mutate Swift struct in background thread

荒凉一梦 提交于 2021-02-07 03:19:00

问题


Assume we have a struct capable of self-mutation that has to happen as part of a background operation:

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

        }

    }
}

Now, when I use such a struct in context:

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

The println gives me 0, as if myThing was never mutated. Printing self.something from within the dispatch_async obviously yields 1.

How do I work around this issue, preferably without having to pass the updated struct's self in the operation competition block and overriding the original variable in the main context?

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

回答1:


I'm adding a second answer because my first answer addressed a different point.

I have just encountered this difficulty myself in circumstances almost identical to yours.

After working and working and working to try to find out what was going on, and fix it, I realized that the problem was, basically, using a value type where a reference type should be used.

The closure seems to create a duplicate of the struct and operate on that, leaving the original untouched--which is more in line with the behavior of a value type.

On the other hand, the desired behavior is for the actions performed in the closure to be retained by the environment outside the closure--in other words two different contexts (inside the closure and out of it) need to refer to the same objects--which is more in line with the behavior of a reference type.

Long story short, I changed the struct to a class. The problem vanished, no other code needed.




回答2:


I have seen this exact problem many times, but without more detail I can't say if it was happening for the same reason that you are having it.

It drove me crazy until I realized that the dispatched operation was taking place at an illogical time, i.e. usually before the current time. In the dispatch block's frame of reference, it correctly updated the variable, which is why it prints out correctly from inside the block. But in the "real world", for some reason, the dispatch is considered to have never happened, and the value change is discarded. Or perhaps it's because the mutation implicitly creates a new struct and because it was "time travelling" the reference to it never updated. Can't say.

In my case, the problem went away once I correctly scheduled the dispatch. I hope that helps!



来源:https://stackoverflow.com/questions/32431050/self-mutate-swift-struct-in-background-thread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!