1. 程式人生 > >Objective-C高階程式設計:iOS與OS X多執行緒和記憶體管理

Objective-C高階程式設計:iOS與OS X多執行緒和記憶體管理

這篇文章主要給大家講解一下GCD的平時不太常用的API,以及文末會貼出GCD定時器的一個小例子。

需要學習的朋友可以通過網盤免費下載pdf版 (先點選普通下載-----再選擇普通使用者就能免費下載了)http://putpan.com/fs/cy1i1beebn7s0h4u9/

1.GCD的API

1.1 Dispatch Queue

要談GCD,就一定要了解Dispatch Queue(執行處理的等待佇列)。
Dispatch Queue按照追加的順序(先進先出FIFO,First-In-First-Out)執行處理。
另外在執行處理是存在兩種Dispatch Queue,一種是等待現在執行中處理的Serial Dispatch Queue

,另一種是不等待現在執行中處理的Concurrent Dispatch Queue

   

1.2 dispatch_queue_create

由於平時在使用時,我們大部分都是使用系統提供的Main Dispatch QueueGlobal Dispatch Queue
所以關於dispatch_queue_createAPI,這裡只說兩點:

  • 通過dispatch_queue_create函式生成的Dispatch Queue在使用結束後要通過dispatch_release
    函式釋放。
  • 如果生成過多的執行緒,就會消耗大量記憶體,大幅度降低系統的響應效能。而使用系統提供的Global Dispatch Queue則不用擔心這個問題。所以除非必要,其他情況建議使用系統提供的Dispatch Queue

1.3 dispatch_set_target_queue

使用dispatch_queue_create函式生成的Dispatch Queue,都使用的是與系統提供的Global Dispatch Queue的預設優先順序相同的優先順序。而要變更生成的執行優先順序的話就要使用dispatch_set_target_queue函式。

在後臺執行動作處理的Serial Dispatch Queue

的生成方法如下:

    dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.example.gcd.mySerialDispatchQueue", NULL);
    dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); dispatch_set_target_queue(mySerialDispatchQueue, globalDispatchQueueBackground); 

1.3 dispatch_after

dispatch_after這裡只說一點,dispatch_after函式並不是在指定時間後執行處理,而只是在指定時間追加處理到Dispatch Queue

因為Main Dispatch Queue在主執行緒的RunLoop中執行,所以在比如每隔1/60秒執行的RunLoop中,Block最快在 3 秒後執行,最慢在 3 秒 + 1/60 秒後執行,並且在Main Dispatch Queue有大量處理追加或主執行緒的處理本身有延遲時,這個時間會更長。

所以該函式在有嚴格時間要求的情況下使用會出現問題,但是隻是想大致延遲執行處理,該函式是非常有效的。

1.4 dispatch_barrier_async

在訪問資料庫或檔案時,使用多執行緒可能會產生資料競爭的問題,當然使用Serial Dispatch Queue可避免資料競爭。

但是如果讀取處理只是與讀取處理並行執行,那麼多個並行執行就不會發生問題。也就是說為了高效率的進行訪問,讀取處理追加到Concurrent Dispatch Queue,寫入處理在任一讀取處理沒有執行的狀態下,追加到Serial Dispatch Queue中即可(在寫入處理結束之前,讀取處理不可執行)。

使用dispatch_barrier_async便可解決這個問題。dispatch_barrier_async函式會等待追加到Concurrent Dispatch Queue上的並行執行的處理全部結束後,再將制定的處理追加到該Concurrent Dispatch Queue中。然後在由dispatch_barrier_async函式追加的處理執行完畢後,Concurrent Dispatch Queue才恢復為一般的動作,追加到該Concurrent Dispatch Queue的處理又開始並行執行。

    dispatch_async(queue, blk0_for_reading);
    dispatch_async(queue, blk1_for_reading);
    dispatch_async(queue, blk2_for_reading);
    dispatch_async(queue, blk3_for_reading);
    dispatch_barrier_async(queue, blk_for_writing); dispatch_async(queue, blk4_for_reading); dispatch_async(queue, blk5_for_reading); dispatch_async(queue, blk6_for_reading); dispatch_async(queue, blk7_for_reading); 

如上所示,使用方法非常簡單。僅使用dispatch_barrier_async函式代替dispatch_async函式即可。

   

1.5 dispatch_apply

dispatch_apply函式是dispatch_sync函式和Dispatch Group的關聯API。該函式按指定的次數將指定的Block追加到指定的Dispatch Queue中,並等待全部處理執行結束。

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(10, queue, ^(size_t index) { NSLog(@"%zu", index); }); NSLog(@"done"); 

例如,該原始碼的執行結果為:

4
1
0
3
5
2
6
8
9
7
done

因為在Global Dispatch Queue中執行處理,所以各個處理的執行時間不定。但是輸出結果中最後的done必定在最後的位置上。這是因為dispatch_apply函式會等待全部處理執行結束。

1.6 Dispatch I/O

大家可能想過,在讀取較大檔案時,如果將檔案分成合適的大小並使用Global Dispatch Queue並列讀取的話,應該會比一般的讀取速度快不少。能實現這一功能的就是Dispatch I/ODispatch Data

   

如果想提高檔案讀取速度,可以嘗試使用Dispatch I/O

1.7 Dispatch Source

GCD中出了主要的Dispatch Queue外,還有不太引人注目的Dispatch Source。它是BSD系核心慣有功能kqueue的包裝。
kqueue是在XNU核心中發生各種事件時,在應用程式程式設計方執行處理的技術。其CPU負荷非常小,儘量不佔用資源。kqueue可以說是應用程式處理XNU核心中發生的各種事件的方法中最優秀的一種。

Dispatch Source可以處理一下事件。

   

在使用NSTimer做定時器的時候,大家應該都知道如果使用不當,會出現記憶體洩漏的問題。
而如果作為一個封裝的元件來說,就需要將NSTimer屬性暴露出來,在控制器銷燬時,呼叫NSTimer的invalidate方法。如果忘記的話就會記憶體洩漏!

 

需要IT程式設計經典書籍資源大合集百度網盤連結的加qq 2057904338,不需要的也可以加喲,本人python全棧工程獅一枚,要諮詢python或者IT行業的朋友可以相互探討學習下,就當交個朋友吧!