ios多線程操作— GCD延遲操作和相關(guān)使用方法

ios多線程操作— GCD延遲操作和相關(guān)使用方法

0x01.iOS版本

使用GCD函數(shù)可以進(jìn)行延時(shí)操作砾淌,該函數(shù)為

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    });

現(xiàn)在我們來(lái)分解一下參數(shù)
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)) : NSEC_PER_SEC
在頭文件中的定義如下:
#define NSEC_PER_SEC 1000000000ull /* nanoseconds per second */
該參數(shù)表示從現(xiàn)在開始經(jīng)過(guò)多少納秒
dispatch_get_main_queue():表示主隊(duì)列. ^{ }:表示一個(gè)block任務(wù)搜骡。
我們可以來(lái)測(cè)試一下經(jīng)過(guò)多少納秒之后掂榔,由主隊(duì)列調(diào)度任務(wù)是異步執(zhí)行還是同步執(zhí)行,代碼如下:

//  when 時(shí)間 從現(xiàn)在開始經(jīng)過(guò)多少納秒
   dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));
   
   void (^task)() = ^ {
       // 延遲操作執(zhí)行的代碼
       NSLog(@"%@", [NSThread currentThread]);
   }; 
   // 經(jīng)過(guò)多少納秒药磺,由主隊(duì)列調(diào)度任務(wù)異步執(zhí)行
   dispatch_after(when, dispatch_get_main_queue(), task);
   // 先執(zhí)行就是異步,后執(zhí)行就是同步
   NSLog(@"come here");

由此可見主隊(duì)列中調(diào)度任務(wù)是異步執(zhí)行的 再將執(zhí)行隊(duì)列改為全局隊(duì)列和串行隊(duì)列,得到的結(jié)果完全是一樣的午绳,由此可知該函數(shù)執(zhí)行的是異步操作。
GCD中有個(gè)函數(shù)能夠保證某段代碼在程序運(yùn)行過(guò)程中只被執(zhí)行1次映之!該函數(shù)如下:

static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
    })

dispatch_once_t在頭文件中得定義如下:typedef long dispatch_once_t; 由此可知該類型是個(gè)long類型拦焚。當(dāng)onceToken等于0時(shí)就會(huì)執(zhí)行block代碼。dispatch_once是線程安全的杠输,只要涉及到線程安全就會(huì)涉及到鎖赎败,dispatch_once內(nèi)部也有一把鎖,性能比互斥鎖高蠢甲! 利用該函數(shù)我們可以來(lái)寫一個(gè)單例模式 單例模式可以保證在程序運(yùn)行過(guò)程僵刮,一個(gè)類只有一個(gè)實(shí)例且該實(shí)例易于供外界訪問(wèn),從而方便控制實(shí)例個(gè)數(shù),并節(jié)約系統(tǒng)資源妓笙,當(dāng)應(yīng)用程序需要共享一份資源時(shí)就可以用單例模式來(lái)實(shí)現(xiàn)若河。單例模式分ARC與MRC兩種情況,我們可以用宏判斷是否為ARC環(huán)境

#if __has_feature(objc_arc)
// ARC
#else
// MRC
#endif

ARC環(huán)境下簡(jiǎn)單地單例模式:

@implementation SoundTools
// 定義一個(gè)靜態(tài)成員寞宫,保存唯一的實(shí)例
static id instance;
 
// 保證對(duì)象只被分配一次內(nèi)存空間萧福,通過(guò)dispatch_once能夠保證單例的分配和初始化是線程安全的
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [super allocWithZone:zone];
    });
    return instance;
}
 
// 保證對(duì)象只被初始化一次
+ (instancetype)sharedSoundTools {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}
 
- (id)copyWithZone:(NSZone *)zone {
    return instance;
}
@end
 
測(cè)試代碼如下:
- (void)viewDidLoad {
    [super viewDidLoad];
     
    SoundTools *s1 = [SoundTools sharedSoundTools];
    NSLog(@"%p", s1);
}
 
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    SoundTools *s2 = [SoundTools sharedSoundTools];
     
    NSLog(@"%p", s2);
}

兩個(gè)方法打印出來(lái)的地址完全一樣!
在MRC環(huán)境下有如下代碼:

// 定義一個(gè)靜態(tài)成員辈赋,保存唯一的實(shí)例
static id instance;
 
// 保證對(duì)象只被分配一次內(nèi)存空間鲫忍,通過(guò)dispatch_once能夠保證單例的分配和初始化是線程安全的
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [super allocWithZone:zone];
    });
    return instance;
}
 
// 保證對(duì)象只被初始化一次
+ (instancetype)sharedSoundTools {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}
 
- (id)copyWithZone:(NSZone *)zone {
    return instance;
}
 
#pragma mark - MRC內(nèi)存管理方法
/**
 因?yàn)閱卫膶?duì)象是保存在靜態(tài)區(qū)的,因此需要重寫 內(nèi)存管理方法钥屈,取消默認(rèn)的引用計(jì)數(shù)操作悟民!
 */
// 默認(rèn)會(huì)將引用計(jì)數(shù)-1
- (oneway void)release {
    // 什么也不做,跟highlight類似
}
 
// 默認(rèn)引用計(jì)數(shù)+1篷就,同時(shí)返回一個(gè)對(duì)象
- (instancetype)retain {
    return instance;
}
 
// 默認(rèn)添加自動(dòng)釋放標(biāo)記射亏,延遲釋放!
- (instancetype)autorelease {
    return instance;
}
 
// 返回有多少個(gè)對(duì)象對(duì)當(dāng)前對(duì)象引用的數(shù)值
- (NSUInteger)retainCount {
    // 出處:limits.h 會(huì)根據(jù)CPU的架構(gòu)自行調(diào)整整數(shù)的長(zhǎng)度
    return ULONG_MAX;
}

0x02.swift 3.0版本

1.延遲執(zhí)行:

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+3.0, execute: {
         [unowned self] () -> Void in
         //延遲操作
     })

PS. DispatchTime對(duì)象用now()獲取當(dāng)前時(shí)間竭业,加上秒數(shù)即可

2.全局隊(duì)列執(zhí)行耗時(shí)操作后切換到主線程刷新UI

DispatchQueue.global().async {
         // 耗時(shí)操作
         DispatchQueue.main.async {
             // 主線程刷新UI
         }
     }

3.同步執(zhí)行操作

     DispatchQueue.global().sync {
         // 同步執(zhí)行
     }

4.創(chuàng)建隊(duì)列
DispatchQueue的默認(rèn)初始化方法創(chuàng)建的是同步隊(duì)列智润,如果要?jiǎng)?chuàng)建并發(fā)的隊(duì)列,在attributes中聲明.concurrent未辆。

     // 同步隊(duì)列
     let serialQueue = DispatchQueue(label: "name")

     // 并發(fā)隊(duì)列
     let concurrentQueue = DispatchQueue(label: "name", attributes: .concurrent)

5.執(zhí)行多個(gè)任務(wù)后再做某種操作
使用DispatchGroup窟绷,所有操作都完成后執(zhí)行notify

     let group = DispatchGroup()

     let queue1 = DispatchQueue(label: "queue1")
     queue1.async(group: group) {
         // 執(zhí)行任務(wù)1
     }
     let queue2 = DispatchQueue(label: "queue2")
     queue1.async(group: group) {
         // 執(zhí)行任務(wù)2
     }

     group.notify(queue: DispatchQueue.main) { 
         // 執(zhí)行完成
     }

如果要在某一任務(wù)或某幾個(gè)任務(wù)后后執(zhí)行其他任務(wù)咐柜,可在任務(wù)間加上等待:

     //等待組內(nèi)任務(wù)全部完成
     group.wait(timeout: DispatchTime.distantFuture)

6.DispatchWorkItem的使用

  • DispatchWorkItem可理解為任務(wù)條目兼蜈,可初始化傳入優(yōu)先級(jí)等參數(shù),因其有默認(rèn)值拙友,也可只傳入一個(gè)閉包为狸。同樣,它也有wait方法献宫,使用和上面差不多钥平。
     let queue = DispatchQueue(label: "queue", attributes: .concurrent)
     let workItem = DispatchWorkItem {
         // 任務(wù)
     }
     queue.async(execute: workItem)
     print("before waiting")
     workItem.wait()
     print("after waiting")

7.barrier柵欄

  • barrier的加入會(huì)等到在它加入隊(duì)列之前的“任務(wù)”執(zhí)行完畢后实撒,才開始執(zhí)行姊途。在它之后加入隊(duì)列的“任務(wù)”,則等到這個(gè)“任務(wù)”執(zhí)行完畢后才開始執(zhí)行知态。這里的“任務(wù)”用DispatchWorkItem創(chuàng)建捷兰。
     let barrierWorkItem = DispatchWorkItem(flags: .barrier) {
         // 柵欄操作,比如之前有若干“讀”操作负敏,這里有“寫”操作
     }
     let queue = DispatchQueue(label: "queue", attributes: .concurrent)
     queue.async(execute: barrierWorkItem)

8.信號(hào)量

為了線程安全的統(tǒng)計(jì)數(shù)量贡茅,會(huì)使用信號(hào)量作計(jì)數(shù)。初始化方法只有一個(gè),傳入一個(gè)Int類型的數(shù)顶考。

     let semaphore = DispatchSemaphore(value: 10)

     // 信號(hào)量減一
     semaphore.wait()

     // 信號(hào)量加一
     semaphore.signal()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末赁还,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子驹沿,更是在濱河造成了極大的恐慌艘策,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渊季,死亡現(xiàn)場(chǎng)離奇詭異朋蔫,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)却汉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門驯妄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人合砂,你說(shuō)我怎么就攤上這事青扔。” “怎么了翩伪?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵赎懦,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我幻工,道長(zhǎng)励两,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任囊颅,我火速辦了婚禮当悔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘踢代。我一直安慰自己盲憎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布胳挎。 她就那樣靜靜地躺著饼疙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪慕爬。 梳的紋絲不亂的頭發(fā)上窑眯,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音医窿,去河邊找鬼磅甩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛姥卢,可吹牛的內(nèi)容都是我干的卷要。 我是一名探鬼主播渣聚,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼僧叉!你這毒婦竟也來(lái)了奕枝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤瓶堕,失蹤者是張志新(化名)和其女友劉穎倍权,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捞烟,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡薄声,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了题画。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片默辨。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖苍息,靈堂內(nèi)的尸體忽然破棺而出缩幸,到底是詐尸還是另有隱情,我是刑警寧澤竞思,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布表谊,位于F島的核電站,受9級(jí)特大地震影響盖喷,放射性物質(zhì)發(fā)生泄漏爆办。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一课梳、第九天 我趴在偏房一處隱蔽的房頂上張望距辆。 院中可真熱鬧,春花似錦暮刃、人聲如沸跨算。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)诸蚕。三九已至,卻和暖如春氧猬,著一層夾襖步出監(jiān)牢的瞬間背犯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工狂窑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留媳板,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓泉哈,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子丛晦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

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