iOS中處理多核併發的技術有兩種分別是:`Grand Central Dispatch`(如下簡稱`GCD`)和`NSOperationQueue`框架。iOS開發的老司機們在程序開發中處理多個任務同時執行的時候,必定都會使用到這兩個框架,並且GCD依靠它簡潔的語法和對block的運用一直很受你們的青睞。ios開發中你必定明白 這樣一條原則:「任何用於界面ui刷新和用戶交互的操做都要放在主線程來操做,任何耗時或者耗CPU的任務必須在異步線程去操做*」,----小白都會問爲什要這樣,老司機都說記住就好-------這裏就簡單解釋下: ios
首先咱們來解釋第一句話:「任何用於界面ui刷新和用戶交互的操做都要放在主線程來操做」,要明白這句話只要明白下面幾個點:1.主線程是線程安全的--把全部ui刷新以及用戶的交互放在主線程操做會避免不少意外狀況的發生,保證在獲取服務端返回的數據時,ui界面能夠及時安全的刷新數據,給用戶帶來良好體驗 。2.ios中只有主線程才能夠馬上刷新ui界面,若是放在異步線程去操做都會形成線程阻塞和延遲的問題。---第二點「任何耗時或者耗CPU的任務必須在異步線程去操做」---若是你很好的明白了前半句,那麼這句話的意思就很好理解了,把耗時或者消耗cpu的操做放在異步線程,也就是爲了防止線程的阻塞延遲,防止主線程上的ui刷新和用戶操做的一系列動做出現卡頓,死鎖,延遲等問題。swift
言歸正傳,咱們繼續往下看,若是你對ios的中的GCD和DispatchQueue 使用很熟練的話,那麼swift3.0的語法和使用應該就是輕車熟路,若是你還不是特別明白GCD是什麼鬼?不要緊,這裏先給你們來點山裏的乾貨:api
1. `dispatch queue`:一堆在主線程(或後臺線程)上同步(或異步)來執行的代碼,一旦被建立出來,操做系統就開始接手管理,在CPU上分配時間片來執行隊列內的代碼。開發者無法參與`queue`的管理。隊列採用`FIFO模式`(先進先出),意味着先加入的也會被先完成,這和超市排隊買單,隊伍前的老是最早買單出去,的道理是同樣同樣的。數組
2. `work item`:一段代碼塊,能夠在queue建立的時候添加,也能夠單首創建方便以後複用,你能夠把它當成將要在`queue`上運行的一個代碼塊。`work items`也遵循着`FIFO模式`,也能夠同步(或異步)執行,若是選擇同步的方式,運行中的程序直到代碼塊完成纔會繼續以後的工做,相對的,若是選擇異步,運行中的程序在觸發了代碼塊就馬上返回了。安全
3. `serial`(串行)vs`concurrent`(並行):`serial`將會執行完一個任務纔會開始下一個,`concurrent`觸發完一個就當即進入下一個,而無論它是否已完成。併發
label:後面是一個標識,能夠隨便寫,通常建議寫成你的工程的dns的反序比較好。框架
而後咱們在viewdidload中執行這個方法,看下控制檯打印的結果:異步
從結果中咱們能夠看到兩個方法是一個一個按順序來執行的,也就是說串行隊列和主線程同樣都是串行輸出的。換句話說也就是:主線程也是一個串行隊列。async
那異步(並行)隊列執行會是怎麼樣呢?函數
看下輸出結果:
此次咱們驚喜地發現和上次不一樣,而且主線程的函數和異步隊列的函數是交替執行 也就是說兩者同步的輸出,這是由於:異步隊列不會阻塞當前線程 而是會另開一個線程來執行當前的任務,而主線程上的任務也就不會被阻塞,因此兩者是同步輸出的。
1. 使用async主線程和後臺線程能夠並行執行任務
2. 使用sync則只能串行執行任務, 當前線程被卡住直到串行任務完成才繼續
弄明白'serial'(串行) 和'concurrent'(並行)的關係,咱們繼續來看下GCD的qos隊列。
GCD服務等級(GCD QoS):肯定任務重要和優先級的屬性
QoS是個基於具體場景的枚舉類型,在初始隊列時,能夠提供合適的QoS參數來獲得相應的權限,若是沒有指定QoS,那麼初始方法會使用隊列提供的默認的QoS值
QoS等級(QoS classes),從前到後,優先級從高到低:
userInteractive
userInitiated
default
utility
background
unspecified
從上面的介紹 咱們猜測 確定是 ---等級越高的隊列越先被執行,同一等級下的隊列中 串行隊列確定是一個一個執行,異步隊列確定是分線程並行執行---下面咱們就來驗證下:
qos:須要傳一個DispatchQoS的枚舉類型
看下輸出結果:
仔細觀察 咱們會發現 結果並無像咱們猜測的那樣 同等級下的異步隊列 並行輸出,這是怎麼回事呢?由於Qos隊列默認是串行執行的,因此即便qos隊列中的方法是異步的 也會被順序串行執行。那麼怎樣才能夠並行執行呢?這就要用到Qos隊列的另一個屬性:attributes:.concurrent
具體寫法:
看下具體函數和運行結果:
經過輸出結果咱們發現 結果是並行輸出了,可是細心的你是否是發現告終果中的一絲絲不一樣,附上的兩張結果圖,是同一個函數運行屢次顯示的不一樣結果,爲何會不一樣呢?難道程序有問題,一個函數怎麼可能有兩個結果呢?是否是頓時一臉懵逼,一萬個草泥馬在心中奔騰😢😢😢😢😢😢😢😢😢😢😢😢😢😢😢😢----施主息怒,待山裏娃慢慢給你分析:
首先咱們要明白系統所謂的並行執行,並不全是咱們想象那的樣是固定的像log1中的同樣十分規矩的輸出,內部是會發生資源的傾斜或者順序的不肯定性的,繼續看下去後面的例子你定會完全明白。
咱們新建一個不一樣等級的Qos隊列來看下結果:
輸出結果:
觀察結果 ,咱們會發現並非咱們以前猜想的 等級越高的隊列會快速先執行完,而是高等級和低等級的交叉進行輸出,仔細想下 其實這就是上面那個問題的完美詮釋,系統會使優先級更高的`queue1`比`queue2`更快被執行,雖然在`queue1`運行的時候`queue2`獲得一個運行的機會,系統仍是將資源傾斜給了被標記爲更重要的`queue1`,等`queue1`內的任務所有被執行完成,系統纔開始全心全意服務於`queue2` 。---看到這裏應該明白了吧。
你們能夠在思考個問題,在這些等級中 main queue主線程隊列是排在哪一個等級呢?下面咱們來看個例子:
結果:
從中咱們能夠清楚的得出結論:`main queue`默認就有一個很高的權限。
接下來咱們在來看下Qos隊列attributes的另一個屬性,initiallyInactive (不活躍的),咱們能夠建立一個qos的不活躍隊列,這個隊列的特色是 須要調用DispatchQueue類的`activate()`讓任務執行。看下具體代碼:
重點在下面,viewdidload中調用:
看下輸出結果:
咱們發現隊列是串行輸出的,那麼怎樣建立一個並行的initiallyInactive 隊列呢?查看api咱們會發現Qos隊列的attributes接收的是一個數組,因此聰明的你確定知道怎麼辦吧😊
當你的應用的某個流程中的某項任務延遲執行,GCD容許你執行某個方法來達到特定時間後運行你指定任務的目的。直接上代碼:
這裏解釋下:.now() 方法 是獲取當前時間。
DispatchWorkItem是一個代碼塊,它能夠被分到任何的隊列,包含的代碼能夠在後臺或主線程中被執行,簡單來講:它被用於替換咱們前面寫的代碼block來調用。使用起來也很簡單,看代碼:
最後給你們分享一個開篇說到的主線程刷新ui的例子,先看代碼:
使用的時候 記得在viewDidLoad 中調用setingIMage() 這個方法。
這裏主要想和你們介紹下swift中的懶加載和oc中的異同,我的總結了下你們能夠參閱:
連接:http://www.jianshu.com/p/737233208d40