2016-01-27 12 views
1

我有以下操場代碼:變異異步塊內INOUT功能放慢參數

import UIKit 
import XCPlayground 

class A { 

    var arr : [UIImage] = [] 

    func addItem(inout localArr: [UIImage]) { 
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(2 * NSEC_PER_SEC)), dispatch_get_main_queue()) {() -> Void in 
      localArr.append(UIImage()) 
      print("from inside function localArr: \(localArr)") 
      print("form inside function: \(self.arr)") 
     } 
    } 
} 

let a = A() 
a.addItem(&a.arr) 
print("instant print :\(a.arr)") 

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(3 * NSEC_PER_SEC)), dispatch_get_main_queue()) {() -> Void in 
    print("print after delay: \(a.arr)") 
} 

XCPlaygroundPage.currentPage.needsIndefiniteExecution = true 

輸出是:

instant print :[] 
from inside function localArr: [<UIImage: 0x7f99e8706f10>, {0, 0}] 
form inside function: [] 
print after delay: [] 

我的問題是,爲什麼localArr不一樣self.arraddItema.arr以外不一樣?我的期望是,當我通過參數inout我應該能夠對實際對象進行操作,而不是副本,但顯然這不是發生的情況。

編輯:所以感謝dfri答案我知道爲什麼這不起作用。 inout確實是call-by-copy-restore,請檢查另一個答案here。現在,有關如何實際使閉包捕獲對原始對象的引用的任何建議?或者也許我應該使用其他技術來實現我想要的?

+0

你的代碼和輸出不match..please編輯 –

+0

編輯,一個print語句從'addItem'內心缺少什麼功能。 – lawicko

回答

2

有關inout關鍵字一些理論,請參閱下面的答案:

不要依賴之間的行爲差​​異拷入拷出 和呼叫引用。

...

當函數返回時,你原來的變化 覆蓋與複製的價值。不要依靠參考呼叫優化的 實施來儘量保持 的改變不被覆蓋。

現在,您addItem功能會立即結束其呼叫,因此之前在功能延遲調度完成inout拷入/複製出任務。這使得使用參數的inout參數的方法中的延遲調度固有的不好,至少如果延遲是試圖改變inout參數的延遲。

爲了看到這一點,讓我們跟蹤一些數組的引用(而不是跟蹤值),以及它們在我們的示例運行時如何顯示數組的變化。

func foo(inout bar: [Int]) { 
    var pBar : UnsafePointer<Int> = UnsafePointer(bar) 
    print("2: \(pBar)") 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(2 * NSEC_PER_SEC)), dispatch_get_main_queue()) {() -> Void in 
     pBar = UnsafePointer(bar) 
     print("3: \(pBar)") 
     bar[0] = 2 
     pBar = UnsafePointer(bar) 
     print("4: \(pBar)") 
    } 
} 

var a : [Int] = [1] 
var pA : UnsafePointer<Int> = UnsafePointer(a) 
print("1: \(pA)") 
foo(&a) 
print("foo call to a finished, a = \(a)") 

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(5 * NSEC_PER_SEC)), dispatch_get_main_queue()) {() -> Void in 
    print("value of a naturally not changed here = \(a)") 
    pA = UnsafePointer(a) 
    print("5: \(pA)") 
} 

XCPlaygroundPage.currentPage.needsIndefiniteExecution = true 

輸出是相當不言自明:

1: 0x00007fe19271e930 
2: 0x00007fe19271e930 
foo call to a finished, a = [1] <-- call to foo finished, 'inout' procedure complete 
3: 0x00007fe19271e930   <-- dispatch in `foo` starts 
4: 0x00007fe1927085e0   <-- mutates 'bar': 'bar' copied (and never 
            "returned" as this step is already finished) 
value of a naturally not changed here = [1] 
5: 0x00007fe19271e930   <-- naturally 'a' wont see the effect of the 
            delayed mutation in foo 
+0

感謝您的解釋,這真的有助於理解'inout'。你有什麼建議如何真正能夠改變數組(或任何其他傳遞的對象)在延遲塊內? – lawicko

+0

@lawicko樂於助人。我必須離開幾個小時,但當我回來的時候我可以看看它,因爲那時沒有其他人幫助你。 – dfri

+0

@lawicko使用引用類型。我相信NSArray會做 –

1

夫特數組是值類型。其中總是複製分配。 如果您想引用原始數組,請使用NSMutableArray。 那麼也沒有必要inout

class A { 

    var arr : NSMutableArray = [] 

    func addItem(localArr: NSMutableArray) { 
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(2 * NSEC_PER_SEC)), dispatch_get_main_queue()) {() -> Void in 
      localArr.addObject(UIImage()) 
      print("from inside function localArr: \(localArr)") 
      print("form inside function: \(self.arr)") 
     } 
    } 
} 

let a = A() 
a.addItem(a.arr) 
print("instant print :\(a.arr)") 

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(3 * NSEC_PER_SEC)), dispatch_get_main_queue()) {() -> Void in 
    print("print after delay: \(a.arr)") 
} 

打印:

instant print :(
) 
from inside function localArr: (
    "<UIImage: 0x7ffe1872b5f0>, {0, 0}" 
) 
form inside function: (
    "<UIImage: 0x7ffe1872b5f0>, {0, 0}" 
) 
print after delay: (
    "<UIImage: 0x7ffe1872b5f0>, {0, 0}" 
) 
+0

謝謝,我已經upvoted你的評論作爲NSMutableArray確實在這種情況下工作。然而,dfri答案實際上解釋了原始問題,這就是爲什麼原始代碼不起作用。 – lawicko

+0

@lawicko我知道;)我只是想在dfri工作時幫助你。 –