2015-09-07 76 views
3

假設我們有能力自我突變的結構有發生作爲後臺操作的一部分:自我變異在後臺線程斯威夫特結構

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

回答

4

我添加了第二個答案,因爲我的第一個答案解決了不同的問題。

我剛剛遇到過這種困難,自己在幾乎與你相同的情況下。

經過工作和工作,努力找出發生了什麼,並解決它,我意識到問題是,基本上,使用值類型應使用引用類型。

閉包似乎創建了一個結構的副本並對其進行操作,從而保持了原始的不變 - 這更符合值類型的行爲。

另一方面,期望的行爲是在閉包中執行的動作由閉包外部的環境保留 - 換句話說,兩個不同的上下文(在閉包內部和外部)需要引用相同的對象 - 這更符合引用類型的行爲。

長話短說,我將結構更改爲一個類。問題消失了,沒有其他代碼需要。

+0

是的,我也得出這樣的結論:我完全濫用結構和做錯怪事。感謝您對此做出詳細的解釋。後人:http://faq.sealedabstract.com/structs_or_classes/ – Arnold

0

我看到這個確切的問題很多次,但沒有更詳細的,如果它發生了,您有這同樣的原因,我不能說。

這讓我發瘋,直到我意識到派出的手術發生在不合邏輯的時間,即通常在當前時間之前。在調度塊的引用框架中,它正確更新了變量,這就是爲什麼它從塊內正確打印出來的原因。但在「現實世界」中,出於某種原因,調度被認爲是從未發生過,並且價值變化被丟棄。或者,也許是因爲突變隱含地創建了一個新的結構,並且因爲它是「時間旅行」,所以對它的引用永遠不會更新。不能說。

在我的情況下,一旦我正確安排了調度,問題就消失了。我希望這有助於!

+0

謝謝,這絕對是一個偉大的領先。 「正確調度調度」的意思是什麼?你是否設置了一個信號量來通知它何時結束? – Arnold

+0

在我的情況下,正確的調度只是意味着在將來而不是過去調度事件。我在Playgrounds中做了大部分工作,並嘗試協調各種可以將dispatch_time_t值傳遞給彼此的移動部件。大量的頭髮拉動之後,我意識到錯誤的關閉計劃會使用dispatch_time_t進行調度,這是在dispatch_after命令收到它之前已經過去的時間。 –