2017-08-01 14 views
1

說我有其中有對象PhotoArray類:數組傳遞由默認與線程安全值

class PhotoManager { 
    fileprivate var _photos: [Photo] = [] 

    var photos: [Photo] { 
     return _photos 
    } 
} 

我讀one article它說以下內容:

默認情況下,在Swift類實例通過引用傳遞並且 結構體按值傳遞。 Swift的內置數據類型(如Array和 Dictionary)以結構體的形式實現。

這意味着上述獲取器返回[Photo]數組的副本。

然後,同一篇文章中試圖使吸氣線程安全的代碼重構到:

fileprivate let concurrentPhotoQueue = DispatchQueue(label: "com.raywenderlich.GooglyPuff.photoQueue", 
                 attributes: .concurrent) 
    fileprivate var _photos: [Photo] = [] 
    var photos: [Photo] { 
    var photosCopy: [Photo]! 
    concurrentPhotoQueue.sync { 
     photosCopy = self._photos 
    } 
    return photosCopy 
    } 

上面的代碼顯式地使self._photos一個副本吸氣。

我的問題是:

  1. 如果默認SWIFT已經返回一個副本(按值傳遞)之類的文章擺在首位,爲什麼文章中複製再次photosCopy,使其線程安全的說?我覺得自己並不完全理解那篇文章中提到的這兩個部分。

  2. Swift3是否真的按照默認值傳遞Array實例如文章所述?

難道有人能爲我澄清嗎?謝謝!

回答

0

1)在代碼示例中,您提供的將返回_photos的副本。 正如在文章中寫道:

The getter for this property is termed a read method as it’s reading 
the mutable array. The caller gets a copy of the array and is protected 
against mutating the original array inappropriately. 

說的是什麼意思,你可以從類的外面訪問_photos,但你可以使他們從那裏不會改變。 photos的值只能在課堂內更改,以防止該數組受到意外更改。

2)是的,Array是一個值類型的結構體,它將按值傳遞。您可以輕鬆地將其簽入遊樂場

let arrayA = [1, 2, 3] 
var arrayB = arrayA 

arrayB[1] = 4 //change second value of arrayB 

print(arrayA) //but arrayA didn't change 

UPD#1

在文章他們有方法func addPhoto(_ photo: Photo)什麼添加新照片_photos陣列是什麼使訪問此屬性不是線程安全的。這意味着什麼值_photos可以在同一時間在幾個線程上更改什麼會導致問題。

他們用.barrierconcurrentQueue寫照片修復它是什麼使它線程安全的,_photos陣列將每一次換一次現在

func addPhoto(_ photo: Photo) { 
    concurrentPhotoQueue.async(flags: .barrier) { // 1 
    self._photos.append(photo) // 2 
    DispatchQueue.main.async { // 3 
     self.postContentAddedNotification() 
    } 
    } 
} 

爲保證線程安全的,你需要閱讀_photos陣列上同一隊列。這就是爲什麼他們重​​構只讀理由方法

+0

我已經發布的兩段代碼,我所問的是1號代碼段,其中的文章說,讀方法返回可變數組的副本,我的困惑是,如果是這樣的話,爲什麼筆者文章重構代碼到第二個代碼片段我張貼明確複製數組返回,如果它是默認情況下已經返回數組的副本? –

+0

@ Leem.fin更新了我的回答 –

+0

感謝您的更新,但它沒有清楚地回答我的問題。你提到的更新是我已經理解的。我的問題只是關於「複製」部分。首先,作者默認在swift中說,array是一個通過值傳遞的結構,這意味着默認情況下,read方法已經返回數組的副本。那麼,爲什麼以後它再次複製數組明確地複製,如果默認情況下它被複制到swift?這聽起來像代碼複製數組兩次。 –

0

我會以相反的解決您的問題:

  • 不Swift3真傳值默認爲類的文章Array實例說?
  • 簡單的答案:是的

    ,但我想這不是你的問題是什麼「的值不Swift3 真的通」問什麼時候。 Swift的行爲好像陣列被完全複製,但在幕後它優化了操作,並且整個陣列不被複制直到和如果需要。 Swift使用稱爲寫時複製(COW)的優化。

    不過,對於斯威夫特程序員做副本怎麼不作爲操作的語義如此重要 - 這是一個分配後/複製兩個數組是獨立的和不斷變化的一個不影響其他。

    1. 如果在默認情況下已經迅速返回一個副本(按值傳遞)之類的文章擺在首位,爲什麼文章中複製再次photosCopy,使其線程安全的說?我覺得自己並不完全理解那篇文章中提到的這兩個部分。

    這段代碼的作用是確保複製是以線程安全的方式完成的。

    的陣列不是一個簡單的值時,它被實施爲多場結構和一些這些字段引用其它結構和/或對象 - 這是需要支持在尺寸上生長的能力的陣列等

    在多線程系統中,當另一個線程嘗試更改數組時,一個線程可能會嘗試複製數組。如果允許這些事件同時發生,那麼事情很容易出錯,例如,數組可能會在複製進行時發生變化,導致無效的複製 - 部分舊值,部分新值。

    斯威夫特本身不是線程安全;尤其是它不會阻止陣列在執行復制時被更改。您通過使用GCD隊列來解決此問題,以便在由一個線程對陣列進行任何更改期間,其他任何線程中的其他寫入或讀取操作都將被阻止,直到更改完成。

    您可能還擔心它們是在這裏進行的多個副本,self._photosphotoCopy,然後是photoCopy到返回值。雖然語義上是這是實際發生的情況,因爲Swift系統會優化,所以可能只有一個複製副本(並且這將是線程安全的)。

    HTH

    +0

    的評論和答案感謝您的解釋。我想我現在明白了! :) –

    +0

    雖然我接受了其他答案,但我建議人們也閱讀@CRD的答案,這也有幫助。 –