iOS 多線程系列 -- GCD全解三(進(jìn)階)

iOS 多線程系列 -- 基礎(chǔ)概述
iOS 多線程系列 -- pthread
iOS 多線程系列 -- NSThread
iOS 多線程系列 -- GCD全解一(基礎(chǔ))
iOS 多線程系列 -- GCD全解二(常用方法)
iOS 多線程系列 -- GCD全解三(進(jìn)階)
iOS 多線程系列 -- NSOperation
測(cè)試Demo的GitHub地址

4. GCD進(jìn)階:

4.1 Dispatch Source 調(diào)度源

4.1.1 Dispatch Source基礎(chǔ)介紹
  • 簡單來說,dispatch source是一個(gè)監(jiān)視某些類型事件的對(duì)象。當(dāng)這些事件發(fā)生時(shí),它會(huì)自動(dòng)將對(duì)應(yīng)的處理程序塊(block)提交給調(diào)度隊(duì)列以響應(yīng)觸發(fā)事件.

  • 調(diào)度源不可重入凫佛。事件源被掛起或當(dāng)事件處理程序塊正在執(zhí)行時(shí)接收到的新事件會(huì)在源恢復(fù)之后或者正在執(zhí)行的程序塊返回后合并/提交.合并機(jī)制的出現(xiàn),是dispatch source為了防止事件積壓到dispatch queue.如果新事件在上一個(gè)事件處理器出列并執(zhí)行之前到達(dá),dispatch source會(huì)將新舊事件的數(shù)據(jù)合并折砸。根據(jù)事件類型的不同,合并操作可能會(huì)替換舊事件,或者更新舊事件的信息(參考下文Dispatch Source自定義事件打印結(jié)果)

  • Dispatch Source有多種類型,不同類型可以實(shí)現(xiàn)不同功能,具體類型如下:

    • Timer
      • DISPATCH_SOURCE_TYPE_TIMER : 定時(shí)器
    • 自定義的事件,并且也是有自己來觸發(fā)
      • DISPATCH_SOURCE_TYPE_DATA_ADD : 合并通過調(diào)用dispatch_source_merge_data()獲得的數(shù)據(jù)
      • DISPATCH_SOURCE_TYPE_DATA_OR : 同樣是合并由dispatch_source_merge_data()獲得的數(shù)據(jù),不過合并原則是按位OR運(yùn)算.
      • 相關(guān)函數(shù)dispatch_source_merge_data()
    • Mach port相關(guān)事件響應(yīng)
      • DISPATCH_SOURCE_TYPE_MACH_SEND : 端口發(fā)送
      • DISPATCH_SOURCE_TYPE_MACH_RECV : 端口接收
    • 文件系統(tǒng)監(jiān)聽
      • DISPATCH_SOURCE_TYPE_VNODE : 文件系統(tǒng)有變更
      • DISPATCH_SOURCE_TYPE_WRITE : 可寫入文件映像
      • DISPATCH_SOURCE_TYPE_READ : 可讀取文件映像
    • 其他
      • DISPATCH_SOURCE_TYPE_SIGNAL : 接收信號(hào)
      • DISPATCH_SOURCE_TYPE_MEMORYPRESSURE : 內(nèi)存壓力
      • DISPATCH_SOURCE_TYPE_PROC : 檢測(cè)到與進(jìn)程相關(guān)的事件
4.1.2 使用Dispatch Source步驟 ,以自定義source事件為例
  • 步驟一: 創(chuàng)建Dispatch Source, 用dispatch_source_create方法

    • 參數(shù)一: Dispatch Source的類別,具體類別上面已介紹
    • 參數(shù)二/三 : 取決于參數(shù)一的配置信息,不同類別的具體配置,可以看頭文件詳細(xì)介紹.
    • 參數(shù)四 : Dispatch Source關(guān)聯(lián)的隊(duì)列
    dispatch_source_create(dispatch_source_type_t type,
        uintptr_t handle,
        unsigned long mask,
        dispatch_queue_t _Nullable queue);
    
    • 創(chuàng)建DISPATCH_SOURCE_TYPE_DATA_ADD類型source
    dispatch_source_t  source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_global_queue(0, 0));
    
    
  • 步驟二: 設(shè)置響應(yīng)事件,每當(dāng)監(jiān)聽到事件后就會(huì)調(diào)用這個(gè)響應(yīng)block

    • 使用dispatch_source_set_event_handler 設(shè)置響應(yīng)事件,參數(shù)一是對(duì)應(yīng)的source,參數(shù)二是響應(yīng)的具體代碼塊
    • dispatch_source_merge_data,向自定義的事件源傳遞一個(gè)unsigned long類型數(shù)據(jù),這個(gè)數(shù)據(jù)可以使用dispatch_source_get_data獲取到,這樣就實(shí)現(xiàn)了事件觸發(fā)到事件響應(yīng)之間的數(shù)據(jù)傳輸
    dispatch_source_set_event_handler(source, ^{
        NSLog(@"%lu 人已報(bào)名",dispatch_source_get_data(source));
    });
  • 步驟三:對(duì)于一個(gè)Dispatch Source還可以設(shè)置取消時(shí)的對(duì)應(yīng)響應(yīng).在這個(gè)source被cancel的時(shí)候調(diào)用.參數(shù)一是對(duì)應(yīng)的source,參數(shù)二是source被cancel時(shí)的響應(yīng)代碼塊
dispatch_source_set_cancel_handler(source, ^{
        NSLog(@"報(bào)名已終止");
    });

  • 步驟三: 恢復(fù)Dispatch Source,新創(chuàng)建的Dispatch Source默認(rèn)掛起,需要恢復(fù)執(zhí)行
    • 恢復(fù)source有兩個(gè)方法dispatch_resume 和dispatch_activate,任選其一,參數(shù)就是要恢復(fù)的source. dispatch_activate是iOS10才添加的新方法,按需使用即可.
dispatch_resume(source);
//dispatch_activate(source);

  • 步驟四: 取消一個(gè)source

    • dispatch_source_cancel,傳入想要取消的source即可. 注意:傳入nill會(huì)閃退,所以調(diào)用之前判斷source是否為nil
    if (self.timer) {
            dispatch_source_cancel(self.timer); // self.timer為nil時(shí)會(huì)閃退
        }
    
    • 如果可能被多線程中調(diào)用此方法,還應(yīng)考慮線程安全,加鎖即可.
    @synchronized (self.timer) {        
        if (self.timer) {
            dispatch_source_cancel(self.timer); // timer為null時(shí)會(huì)閃退
        }
    }
    
  • 示例代碼:

dispatch_source_t  source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0,dispatch_get_main_queue());
    dispatch_source_set_event_handler(source, ^{
        NSLog(@"%lu 人已報(bào)名",dispatch_source_get_data(source));
    });
    dispatch_resume(source);
    dispatch_apply(5, dispatch_get_global_queue(0, 0), ^(size_t index) {
        NSLog(@"用戶%zd 報(bào)名郊游",index);
        dispatch_source_merge_data(source, 1); // 觸發(fā)事件,傳遞數(shù)據(jù)
    });
  • 打印結(jié)果
2017-07-01 18:34:30.514 Test - 多線程[66363:2522266] 用戶2 報(bào)名郊游
2017-07-01 18:34:30.513 Test - 多線程[66363:2522111] 用戶0 報(bào)名郊游
2017-07-01 18:34:30.513 Test - 多線程[66363:2522265] 用戶1 報(bào)名郊游
2017-07-01 18:34:30.514 Test - 多線程[66363:2522359] 用戶3 報(bào)名郊游
2017-07-01 18:34:30.514 Test - 多線程[66363:2522266] 用戶4 報(bào)名郊游
2017-07-01 18:34:30.514 Test - 多線程[66363:2522111] 5 人已報(bào)名

  • Dispatch Source進(jìn)階分析
    • 細(xì)心的同學(xué)會(huì)發(fā)現(xiàn)上面的打印結(jié)果很有意思,有五個(gè)用戶報(bào)名,結(jié)果統(tǒng)計(jì)人數(shù)打印只有一次,為什么不是五次?難道不應(yīng)該報(bào)名一次統(tǒng)計(jì)一次嘛?這就是為什么使用Dispatch Source的原因所在,分析如下:
    • 主線程只不過是GCD的另一個(gè)dispatch queue,我們把大量的響應(yīng)工作push到主線程中,主線程每一次都處理響應(yīng)事件可能會(huì)消耗很多資源,我們不想對(duì)響應(yīng)工作進(jìn)行頻繁而累贅的更新吧恃,理想的情況是當(dāng)主線程繁忙時(shí)將所有的響應(yīng)工作聯(lián)結(jié)起來。這時(shí)用dispatch source就完美了,使用DISPATCH_SOURCE_TYPE_DATA_ADD,我們可以將工作拼接起來言疗,然后主線程可以知道從上一次處理完事件到現(xiàn)在一共發(fā)生了多少改變,然后將這一整段改變一次更新至最新進(jìn)度.所以從打印結(jié)果可以看到,系統(tǒng)把五次響應(yīng)聯(lián)結(jié)起來,組成了一次任務(wù)輸出,這在節(jié)省性能方面很有幫助!
4.1.3 使用Dispatch Source自定義定時(shí)器

在上面提到的幾個(gè)步驟的基礎(chǔ)上,還需要使用,dispatch_source_set_timer設(shè)置定時(shí)器屬性,當(dāng)然創(chuàng)建source的類型要選擇DISPATCH_SOURCE_TYPE_TIMER

  • dispatch_source_set_timer方法這是定時(shí)器屬性,參數(shù)解析:
    • 第一個(gè)參數(shù):dispatch_source_t 創(chuàng)建的定時(shí)器類型source
    • 第二個(gè)參數(shù):dispatch_time_t start, 定時(shí)器開始時(shí)間,類型為 dispatch_time_t,dispatch_time_t有兩個(gè)創(chuàng)建方法,分別是:dispatch_time和dispatch_walltime,區(qū)別介紹如下:
      • 當(dāng)我們?cè)O(shè)置為dispatch_time 或者 DISPATCH_TIME_NOW 時(shí),系統(tǒng)會(huì)使用默認(rèn)時(shí)鐘來進(jìn)行計(jì)時(shí)颂砸。然而當(dāng)系統(tǒng)休眠的時(shí)候,默認(rèn)時(shí)鐘是不走的,也就會(huì)導(dǎo)致計(jì)時(shí)器停止
      • 同為設(shè)置時(shí)間,但是dispatch_w,alltime為“鐘表”時(shí)間,相對(duì)比較準(zhǔn)確,所以選擇使用后者噪奄。dispatch_walltime有兩個(gè)參數(shù)
        • 參數(shù)when可以為Null/DISPATCH_TIME_NOW,默認(rèn)為獲取當(dāng)前時(shí)間;
        • 參數(shù)delta為增量,注意delta的單位是納秒.即獲取當(dāng)前時(shí)間的基礎(chǔ)上,增加delta納秒的時(shí)間為開始計(jì)時(shí)時(shí)間.如果想要延遲1秒的話,那就是1000000000這樣寫太長了,系統(tǒng)理所當(dāng)然的提供了對(duì)應(yīng)的常量宏.關(guān)鍵字解釋:NSEC納秒,PER每,SEC秒,MSEC毫秒,USEC微秒.所以NSEC_PER_SEC的意思是每秒有多少納秒,那么延遲1秒就可以寫成1* NSEC_PER_SEC
      • 介紹兩個(gè)常用dispatch_time_t宏,ull表示unsigned long long類型,~表示按位取反. 所以就能理解DISPATCH_TIME_NOW = 0, DISPATCH_TIME_FOREVER至少是一個(gè)不小于2^64 - 1的數(shù)值
    • 第三個(gè)參數(shù):uint64_t interval,定時(shí)器間隔時(shí)長,由業(yè)務(wù)需求而定死姚。
    • 第四個(gè)參數(shù):uint64_t leeway, 允許誤差,此處傳0即可,需要注意,就算指定 leeway 值為 0,系統(tǒng)也無法保證完全精確的觸發(fā)時(shí)間,只是會(huì)盡可能滿足這個(gè)需求。
        dispatch_time_t dispatch_time(dispatch_time_t when, int64_t delta);
    dispatch_time_t dispatch_walltime(const struct timespec *_Nullable when, int64_t delta);

            #define NSEC_PER_SEC 1000000000ull
            #define NSEC_PER_MSEC 1000000ull
            #define USEC_PER_SEC 1000000ull
            #define NSEC_PER_USEC 1000ull
        #define DISPATCH_TIME_NOW (0ull)
        #define DISPATCH_TIME_FOREVER (~0ull)

  • GCD定時(shí)器示例代碼:

- (void)dispatchTimer
{
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
    _timer = timer;
    //NSEC_PER_SEC宏其定義是1000000000納秒,也就是1秒
    dispatch_source_set_timer(timer, dispatch_walltime(DISPATCH_TIME_NOW,1 * NSEC_PER_SEC), 1ull * NSEC_PER_SEC, 0);
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"-----handle dispatchTimer thread = %@",[NSThread currentThread]);
    });
    dispatch_source_set_cancel_handler(timer, ^{
        NSLog(@"-----cancel dispatchTimer thread = %@",[NSThread currentThread]);
    });
    dispatch_resume(timer);//啟動(dòng)定時(shí)器
}
4.1.4 Dispatch Source補(bǔ)充

4.2 dispatch semaphore

信號(hào)量是一個(gè)整形值并且具有一個(gè)初始計(jì)數(shù)值勤篮,并且支持兩個(gè)操作:信號(hào)通知(dispatch_semaphore_signal)和等待(dispatch_semaphore_wait).

4.2.1 操作dispatch semaphore的三個(gè)方法
  • dispatch_semaphore_create   創(chuàng)建一個(gè)semaphore,有一個(gè)long類型的參數(shù)value,表示這個(gè)信號(hào)量的初始值,注意: value的值不能小于0,否則創(chuàng)建失敗返回NULL.
dispatch_semaphore_t dispatch_semaphore_create(long value);
  • dispatch_semaphore_wait   讓信號(hào)值減1,等待信號(hào).參數(shù)dsema表示要操作的信號(hào)量, timeout為等待時(shí)間.讓信號(hào)值減1后這個(gè)方法有兩種處理操作:
    • 如果信號(hào)值減1后值小于0,阻塞線程直到信號(hào)值不小于0為止,什么時(shí)候線程被喚醒是在dispatch_semaphore_signal方法中處理的
    • 如果信號(hào)值減1后值大于等于0,繼續(xù)往下執(zhí)行,不阻塞線程
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
  • dispatch_semaphore_signal   讓信號(hào)值加1,發(fā)送一個(gè)信號(hào),參數(shù)dsema表示信號(hào)值要加1的信號(hào)量.如果信號(hào)量在加1之前小于0, 會(huì)喚醒這個(gè)被阻塞的線程.喚醒成功返回一個(gè)非零的值,否則返回0.
long dispatch_semaphore_signal(dispatch_semaphore_t dsema);

4.2.2 進(jìn)階 - dispatch semaphore的實(shí)用場(chǎng)景

上面已經(jīng)介紹dispatch semaphore的基本使用方法,那利用dispatch semaphore可以實(shí)現(xiàn)那些功能?

  • dispatch semaphore實(shí)現(xiàn)GCD線程并發(fā)控制

    • NSOperationQueue中可以利用maxConcurrentOperationCount設(shè)置最大并發(fā)數(shù),GCD中如何實(shí)現(xiàn)最大并發(fā)數(shù)量的控制呢? 我們可以利用dispatch semaphore實(shí)現(xiàn)GCD線程并發(fā)控制,如下代碼: 調(diào)度組中最多有3個(gè)queue任務(wù)在執(zhí)行,只有執(zhí)行完一個(gè)才能添加另一個(gè)到調(diào)度組,進(jìn)而實(shí)現(xiàn)并發(fā)控制
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
        dispatch_group_t group = dispatch_group_create();
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);        
        for (int i = 0; i < 100; i++)
        {
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            dispatch_group_async(group, queue, ^{
                sleep(5);
                NSLog(@"結(jié)束任務(wù)i = %d , thread = %@",i,[NSThread currentThread]);
                dispatch_semaphore_signal(semaphore);
            });
        }
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    }); 
    
  • 控制共有資源的多線程訪問數(shù)據(jù)安全

    • 如果多個(gè)線程同時(shí)操縱一份共有資源,會(huì)引發(fā)數(shù)據(jù)錯(cuò)誤的問題.使用dispatch_semaphore_create(1) 創(chuàng)建一個(gè)同一時(shí)間只允許一個(gè)線程操縱數(shù)據(jù)的信號(hào)量即可保證數(shù)據(jù)的安全.其實(shí)有點(diǎn)類似于線機(jī)制,一種線程同步技術(shù).
    • 示例代碼,保證數(shù)組內(nèi)用戶插入順序如下:
    // 保證用戶的插入順序
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    NSMutableArray *users = [NSMutableArray array];
    for (int i = 0; i < 300; i++) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(){
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
             // 訪問共有資源的任務(wù)代碼
            NSLog(@"i = %zd , 添加一個(gè)用戶,thread = %@",i,[NSThread currentThread]);
            [users addObject:@(i)];
            dispatch_semaphore_signal(semaphore);
        });
    }
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末知允,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子叙谨,更是在濱河造成了極大的恐慌,老刑警劉巖保屯,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件手负,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡姑尺,警方通過查閱死者的電腦和手機(jī)竟终,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來切蟋,“玉大人统捶,你說我怎么就攤上這事”猓” “怎么了喘鸟?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長驻右。 經(jīng)常有香客問我什黑,道長,這世上最難降的妖魔是什么堪夭? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任愕把,我火速辦了婚禮,結(jié)果婚禮上森爽,老公的妹妹穿的比我還像新娘恨豁。我一直安慰自己,他們只是感情好爬迟,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布橘蜜。 她就那樣靜靜地躺著,像睡著了一般雕旨。 火紅的嫁衣襯著肌膚如雪扮匠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天凡涩,我揣著相機(jī)與錄音棒搜,去河邊找鬼。 笑死活箕,一個(gè)胖子當(dāng)著我的面吹牛力麸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼克蚂,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼闺鲸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起埃叭,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤摸恍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后赤屋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體立镶,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年类早,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了媚媒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡涩僻,死狀恐怖缭召,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情逆日,我是刑警寧澤嵌巷,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站室抽,受9級(jí)特大地震影響晴竞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜狠半,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一噩死、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧神年,春花似錦已维、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至飘千,卻和暖如春堂鲜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背护奈。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來泰國打工缔莲, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人霉旗。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓痴奏,卻偏偏與公主長得像蛀骇,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子读拆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • Dispatch Sources 現(xiàn)代系統(tǒng)通常提供異步接口擅憔,允許應(yīng)用向系統(tǒng)提交請(qǐng)求,然后在系統(tǒng)處理請(qǐng)求時(shí)應(yīng)用可以繼...
    YangPu閱讀 305評(píng)論 0 0
  • 什么是GCD檐晕? Grand Central Dispatch(GCD)是蘋果開發(fā)的一項(xiàng)技術(shù)暑诸,用于提升應(yīng)用在多核處理...
    rapunzelyeah閱讀 268評(píng)論 0 1
  • 程序中同步和異步是什么意思?有什么區(qū)別辟灰? 解釋一:異步調(diào)用是通過使用單獨(dú)的線程執(zhí)行的屠列。原始線程啟動(dòng)異步調(diào)用,異步調(diào)...
    風(fēng)繼續(xù)吹0閱讀 1,032評(píng)論 1 2
  • Dispatch Sources 現(xiàn)代系統(tǒng)通常提供異步接口伞矩,允許應(yīng)用向系統(tǒng)提交請(qǐng)求,然后在系統(tǒng)處理請(qǐng)求時(shí)應(yīng)用可以繼...
    好雨知時(shí)節(jié)浩宇閱讀 3,819評(píng)論 2 5
  • Dispatch Queues dispatch queues是執(zhí)行任務(wù)的強(qiáng)大工具夏志,允許你同步或異步地執(zhí)行任意代碼...
    YangPu閱讀 644評(píng)論 0 4