swift
中的值型別
在swift
中不同於oc
,陣列和字典等都被定義為了值型別,而與之對應的類屬於引用型別。當然值型別還包括結構體和列舉。值型別有一個優點就是執行緒安全,本篇也只討論其執行緒安全的問題。
一個有趣的例子
有這樣一段程式碼,判斷下輸出結果以及會不會crash:
let queue = DispatchQueue.global()
var animals = ["dog", "cat", "pig"]
queue.async {
let count = animals.count
for index in 0 ..< count {
print("\(animals[index])")
Thread.sleep(forTimeInterval: 1)
}
}
queue.async {
Thread.sleep(forTimeInterval: 0.5)
animals.remove(at: 0)
}
複製程式碼
執行結果會列印出來dog
、pig
然後crash掉了,報錯資訊:
Thread 4: Fatal error: Index out of range。
複製程式碼
原因就是我們在讀取陣列第二個元素時,第一個元素被移除掉了,所以會列印出來pig
。然後當讀取第三個元素時,陣列內已無第三個元素,所以就會越界crash。那麼是不是就意味著值型別並不是執行緒安全的呢?
真實的執行緒安全
通過上面的例子不難看出值型別的陣列在這種多執行緒讀寫的情況下並不是執行緒安全的。我們所說的執行緒安全是這樣的:
queue.async { [animals] in
let count = animals.count
for index in 0 ..< count {
print("\(animals[index])")
Thread.sleep(forTimeInterval: 1)
}
}
複製程式碼
通過對這段程式碼的修改我們就可以得到想要的結果,並且不會crash。因為此時在新的執行緒中會copy
出一份新的animals
。所以當執行緒會copy
值型別內容時是執行緒安全的,其他情況會存線上程不安全的隱患,我們使用時應當注意。