GCD簡介

什麼是GCD

全稱是Grand Central Dispatch,可譯爲「牛逼的中樞調度器」
純C語言,提供了很是多強大的函數
 
  • GCD的優點
  1. GCD是蘋果公司爲多核的並行運算提出的解決方案
  2. GCD會自動利用更多的CPU內核(好比雙核、四核)
  3. GCD會自動管理線程的生命週期(建立線程、調度任務、銷燬線程)
  4. 程序員只須要告訴GCD想要執行什麼任務,不須要編寫任何線程管理代碼

任務和隊列

  • GCD中有2個核心概念
  1. 任務:執行什麼操做
  2. 隊列:用來存聽任務
 
  • GCD的使用就2個步驟
  1. 定製任務
  2. 肯定想作的事情

 

  • 任務添加到隊列
  1. GCD會自動將隊列中的任務取出,放到對應的線程中執行
  2. 任務的取出遵循隊列FIFO原則:先進先出,後進後出

GCD中有2個用來執行任務的函數

  • 同步的方式執行任務

dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);程序員

queue:隊列
block:任務

 

  • 異步的方式執行任務

dispatch_async(dispatch_queue_t queue, dispatch_block_t block);安全

 

  • 同步和異步的區別
同步:只能在 當前線程中執行任務, 不具有開啓新線程的能力
異步:能夠在 新的線程中執行任務, 具有開啓新線程的能力

隊列的類型

GCD的隊列能夠分爲2大類型

併發隊列(Concurrent Dispatch Queue)

  • 可讓多個任務併發(同時)執行(自動開啓多個線程同時執行任務)
  • 併發功能只有在異步(dispatch_async)函數下才有效

 

串行隊列(Serial Dispatch Queue)

  • 讓任務一個接着一個地執行(一個任務執行完畢後,再執行下一個任務)

容易混淆的術語

有4個術語比較容易混淆:同步、異步、併發、串行

同步異步主要影響:能不能開啓新的線程
同步:在當前線程中執行任務, 不具有開啓新線程的能力
異步:在新的線程中執行任務, 具有開啓新線程的能力
 
併發串行主要影響:任務的執行方式
併發:多個任務併發(同時)執行
串行:一個任務執行完畢後,再執行下一個任務

併發隊列

  • GCD默認已經提供了全局的併發隊列,供整個應用使用,不須要手動建立
使用dispatch_get_global_queue函數得到全局的併發隊列
dispatch_queue_t dispatch_get_global_queue(
dispatch_queue_priority_t priority, // 隊列的優先級
unsigned long flags); // 此參數暫時無用,用0便可
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 得到全局併發隊列

全局併發隊列的優先級
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 //
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默認(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) //
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 後臺

 

串行隊列

GCD中得到串行有2種途徑
使用dispatch_queue_create函數建立串行隊列
dispatch_queue_t
dispatch_queue_create(const char *label, // 隊列名稱 
dispatch_queue_attr_t attr); // 隊列屬性,通常用NULL便可
dispatch_queue_t queue = dispatch_queue_create("cn.itcast.queue", NULL); // 建立
dispatch_release(queue); // 非ARC須要釋放手動建立的隊列

使用主隊列(跟主線程相關聯的隊列)
主隊列是GCD自帶的一種特殊的串行隊列
放在主隊列中的任務,都會放到主線程中執行
使用dispatch_get_main_queue()得到主隊列
dispatch_queue_t queue = dispatch_get_main_queue();

 

各類隊列的執行效果

 

注意併發

  • 使用sync函數往當前串行隊列中添加任務,會卡住當前的串行隊列

 

線程間通訊示例

// 從子線程回到主線程
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 執行耗時的異步操做...
      dispatch_async(dispatch_get_main_queue(), ^{
        // 回到主線程,執行UI刷新操做
        });
});

延時執行

// iOS常見的延時執行有2種方式
// 調用NSObject的方法
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
// 2秒後再調用self的run方法

// 使用GCD函數
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    // 2秒後異步執行這裏的代碼...

});

一次性代碼

// 使用dispatch_once函數能保證某段代碼在程序運行過程當中只被執行1次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // 只執行1次的代碼(這裏面默認是線程安全的)
});

隊列組

// 有這麼1種需求
// 首先:分別異步執行2個耗時的操做
// 其次:等2個異步操做都執行完畢後,再回到主線程執行操做

// 若是想要快速高效地實現上述需求,能夠考慮用隊列組
dispatch_group_t group =  dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 執行1個耗時的異步操做
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 執行1個耗時的異步操做
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    // 等前面的異步操做都執行完畢後,回到主線程...
});

單例模式

  • 單例模式的做用
  1. 能夠保證在程序運行過程,一個類只有一個實例,並且該實例易於供外界訪問
  2. 從而方便地控制了實例個數,並節約系統資源
 
  • 單例模式的使用場合
  1. 在整個應用程序中,共享一份資源(這份資源只須要建立初始化1次)
  • 單例模式在ARC\MRC環境下的寫法有所不一樣,須要編寫2套不一樣的代碼
  1. 能夠用宏判斷是否爲ARC環境
#if __has_feature(objc_arc)
// ARC
#else
// MRC
#endif

單例模式 - ARC

// ARC中,單例模式的實現
// 在.m中保留一個全局的static的實例
// static id _instance;

// 重寫allocWithZone:方法,在這裏建立惟一的實例(注意線程安全)
+ (id)allocWithZone:(struct _NSZone *)zone
{
    @synchronized(self) {
        if (!_instance) {
            _instance = [super allocWithZone:zone];
        }
    }
    return _instance;
}
// 提供1個類方法讓外界訪問惟一的實例
+ (instancetype)sharedSoundTool
{
    @synchronized(self) {
        if (!_instance) {
            _instance = [[self alloc] init];
        }
    }
    return _instance;
}
// 實現copyWithZone:方法
- (id)copyWithZone:(struct _NSZone *)zone
{
    return _instance;
}

單例模式 – 非ARC

// 非ARC中(MRC),單例模式的實現(比ARC多了幾個步驟)
// 實現內存管理方法
- (id)retain { return self; }
- (NSUInteger)retainCount { return 1; }
- (oneway void)release {}
- (id)autorelease { return self; }
相關文章
相關標籤/搜索