iOS GCD(二)

上篇記錄了GCD的各種基本使用方法及特點,下面是GCD在項目中的常用場景


1、創建單例 dispatch_once

static People *sharePeople = nil;
+ (instancetype)sharePeople{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"oncetoken");//這裏的代碼只會執行一次
        sharePeople = [[self alloc]init];
    });
    return sharePeople;
}

2、延遲執行   dispatch_after (異步)

函數原型

參數 when 延遲執行的時間

參數 quene 在哪個隊列中執行

參數 block 延遲執行的內容

dispatch_after(dispatch_time_t when,
	dispatch_queue_t queue,
	dispatch_block_t block);
    NSLog(@"開始");
    double delayInSeconds = 2.0;
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW,delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, mainQueue, ^{
        NSLog(@"延時執行的2秒");
    });
    NSLog(@"結束");
執行結果:

2016-12-27 15:37:32.509 GCD[1547:228385] 開始
2016-12-27 15:37:32.509 GCD[1547:228385] 結束
2016-12-27 15:37:34.510 GCD[1547:228385] 延時執行的2秒

注意:延遲執行在iOS中一般還可以通過下面的方法或者NSTimer來實現

- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;

但這個方法並不是安全的,因爲這個方法或者是NSTimer都需要有一個runloop來實現,而只有主線程在創建的時候回默認自動運行一個runloop,普通的子線程是沒有的,一旦這兩種方式在子線程中調用,則延遲方法裏面的內容就永遠不會執行。

相對來說GCD是安全的

3、併發地執行循環迭代 dispatch_apply

         代替for循環  要求,循環次數固定並且循環執行的次序無關,這是可以用dispatch_apply提高效率(併發執行)

         原來的for循環

int i;
    int count = 10;
    for (i = 0; i < count; i++) {
        printf("%d  ",i);
    }
這是輸出

0  1  2  3  4  5  6  7  8  9  

同dispatch_apply代替

 // 獲得全局併發queue
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    size_t count = 10;
    dispatch_apply(count, queue, ^(size_t i) {
        printf("%zd ", i);
    });
可能就會輸出

0 1 3 2 4 5 6 8 7 9  

4、在子線程中調用下載圖片等耗時操作,下載完成後在主線程刷新界面

// 異步下載圖片
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSURL *url = [NSURL URLWithString:@"http://image.baidu.com/search/detail?ct=503316480&z=0&tn=baiduimagedetail&ipn=d&cl=2&cm=1&sc=0&lm=-1&ie=gbk&pn=0&rn=1&di=20652390440&ln=30&word=ͼƬ&os=3812566282,1648699000&cs=214931719,1608091472&objurl=http%3A%2F%2F4493bz.1985t.com%2Fuploads%2Fallimg%2F150127%2F4-15012G52133.jpg&bdtype=0&simid=3354004378,369260611&pi=0&adpicid=0&fr=ala&ala=1&alatpl=others&pos=1"];
        UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
        
        // 回到主線程顯示圖片
        dispatch_async(dispatch_get_main_queue(), ^{
            self.imageView.image = image;
        });  
    });

這裏可能會有這種情況,某界面需要兩張或多張圖片,當所有的圖片加載完成後才刷新界面,這時可以用Dispatch Group來實現

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    // 異步下載圖片
    dispatch_async(queue, ^{
        // 創建一個組
        dispatch_group_t group = dispatch_group_create();
        
        __block UIImage *image1 = nil;
        __block UIImage *image2 = nil;
        
        // 關聯一個任務到group
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            // 下載第一張圖片
            NSString *url1 = @"http://car0.autoimg.cn/upload/spec/9579/u_20120110174805627264.jpg";
            image1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url1]]];
        });
        
        // 關聯一個任務到group
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            // 下載第一張圖片
            NSString *url2 = @"http://hiphotos.baidu.com/lvpics/pic/item/3a86813d1fa41768bba16746.jpg";
            image2 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url2]]];
        });
        
        // 等待組中的任務執行完畢,回到主線程執行block回調
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            self.imageView1.image = image1;
            self.imageView2.image = image2;
            
            // 千萬不要在異步線程中自動釋放UIImage,因爲當異步線程結束,異步線程的自動釋放池也會被銷燬,那麼UIImage也會被銷燬
        });
    });




發佈了38 篇原創文章 · 獲贊 19 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章