IOS多執行緒之(GCD)

JOily_H發表於2021-03-03

Grand Central Dispatch (GCD)是Apple開發的一個多核程式設計的解決方法

1.常用的方法dispatch_async 耗時的操作

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

// 耗時的操作 

dispatch_async(dispatch_get_main_queue(), ^{ 

    // 更新介面 

}); 

});

1.Dispatch Group的使用

  • (void)downloadImages {

    並行執行

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

      // 下載第一張圖片  
    
      NSString *url1 = @"<http://car0.autoimg.cn/upload/spec/9579/u_20120110174805627264.jpg>";  
    
      UIImage *image1 = [self imageWithURLString:url1];  
    
      // 下載第二張圖片  
    
      NSString *url2 = @"<http://hiphotos.baidu.com/lvpics/pic/item/3a86813d1fa41768bba16746.jpg>";  
    
      UIImage *image2 = [self imageWithURLString:url2];  
    
      // 回到主執行緒顯示圖片  
    
      dispatch_async(dispatch_get_main_queue(), ^{  
    
          self.imageView1.image = image1;  
    
          self.imageView2.image = image2;  
    
      });  

    });

}

兩張圖片的下載過程並不需要按順序執行,併發執行它們可以提高執行速度

+(void)dispatch{

//得到佇列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(queue, ^{

    // 耗時的操作

    //  建立一個組

    dispatch_group_t group = dispatch_group_create();

    // 建立一組任務

    dispatch_group_async(group, queue, ^{

        NSLog(@"並行執行執行緒一");

    });

    // 建立二組任

    dispatch_group_async(group, queue, ^{

        NSLog(@"並行執行執行緒二");

    });

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{

        // 更新介面

        NSLog(@"主執行緒更新介面");

    });

});

}

/// 另一種寫法

  • (void)requestDatasGroup {

    // 建立排程組

    dispatch_group_t group = dispatch_group_create();

    // 建立佇列

    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    dispatch_group_enter(group);

    dispatch_async(queue, ^{

      NSLog(@"介面 A 資料請求完成");
    
      dispatch_group_leave(group);

    });

    dispatch_group_enter(group);

    dispatch_async(queue, ^{

      NSLog(@"介面 B 資料請求完成");
    
      dispatch_group_leave(group);

    });

    NSLog(@”我是最開始執行的,非同步操作裡的列印是後執行的”);

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{

      NSLog(@"介面 A 和介面 B 的資料請求都已經完畢!, 開始合併兩個介面的資料");

    });

}

3、dispatch_barrier_async的使用

順序執行

dispatch_barrier_async是在前面的任務執行結束後它才執行,而且它後面的任務等它執行完成之後才會執行

例子程式碼如下

dispatch_queue_t queue = dispatch_queue_create(“gcdtest.rongfzh.yc”, DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{

[NSThread sleepForTimeInterval:2]; 

NSLog(@"dispatch_async1"); 

});

dispatch_async(queue, ^{

[NSThread sleepForTimeInterval:4]; 

NSLog(@"dispatch_async2"); 

});

dispatch_barrier_async(queue, ^{

NSLog(@"dispatch_barrier_async"); 

[NSThread sleepForTimeInterval:4]; 

});

dispatch_async(queue, ^{

[NSThread sleepForTimeInterval:1]; 

NSLog(@"dispatch_async3"); 

});

列印結果:

2012-09-25 16:20:33.967 gcdTest[45547:11203] dispatch_async1

2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_async2

2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_barrier_async

2012-09-25 16:20:40.970 gcdTest[45547:11303] dispatch_async3

4、dispatch_apply

執行某個程式碼片段N次。

dispatch_apply(5, globalQ, ^(size_t index) {

// 執行5次

});

5,gcd 延時操作

dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0/延遲執行時間/ * NSEC_PER_SEC));

    dispatch_after(delayTime, dispatch_get_main_queue(), ^{

        [self reciveNotification:userInfo];

    });

其他方法

#pragma mark 第一種解決縣城的問題的方法,nsobject提供的方法

-(void)NSObjectThread:(UIButton *)button{

[self performSelectorInBackground:@selector(click:) withObject:button];

 //優點:寫法特別簡單.能快速開闢一個臨時執行緒

 //缺點:不能保證執行緒使用時資料的絕對安全

}

#pragma mark 第二種方式

-(void)NSThreadAction:(UIButton *)button{

//NSThread 本身就是一個執行緒類,它可以控制執行緒休眠或者建立..

//當前的主執行緒

NSLog(@"%@",[NSThread currentThread]);

//主執行緒休眠3s

// [NSThread sleepForTimeInterval:3];

// NSLog(@”0002112121”);

//如果用建立物件,建立出來的就是新的執行緒..

NSThread *thread=[[[NSThread alloc] initWithTarget:self selector:@selector(click:) object:nil] autorelease];

//可以給新的執行緒物件起名

thread.name=@"kitty";

//啟動子執行緒.

[thread start];

//優點:可以直接通過建立的方式來控制執行緒.

//缺點:什麼都需要手動設定,包括名,開始.太麻煩..

}

#pragma mark 第三種 NSOperation 任務

-(void)operationQueue:(UIButton *)button{

//佇列和任務一起配合使用解決多執行緒的問題..

//佇列:佇列中通過一個執行緒池來管理所有閒置的執行緒,這樣就可以提高執行緒的重用率,避免重複的建立執行緒,,整合資源

//優點:內部不需要關心執行緒的安全問題,用起來相對簡單//

//缺點:效率稍微優點低...

NSOperationQueue *queue=[[NSOperationQueue alloc] init];

//設定最大併發數..

[queue setMaxConcurrentOperationCount:2];

MyOperation *op1=[[MyOperation alloc] init];

MyOperation *op2=[[MyOperation alloc] init];

MyOperation *op3=[[MyOperation alloc] init];

MyOperation *op4=[[MyOperation alloc] init];

MyOperation *op5=[[MyOperation alloc] init];

//把任務加到佇列裡

 [queue addOperation:op1];

 [queue addOperation:op2];

 [queue addOperation:op3];

 [queue addOperation:op4];

 [queue addOperation:op5];

}

=============

MyOperation 繼承於 NSOperation

@implementation MyOperation

-(void)main{

// 要執行的操作。。

}

@end

//利用GCD的dispatch_once的方法實現單利模式

  • (instancetype)defaultManager {

staticMusicPlayerViewController *_instance =nil;

staticdispatch_once_tonceToken;

dispatch_once(&onceToken, ^{

_instance = [[selfalloc] init];

});

return_instance;

}

6.後臺執行

GCD的另一個用處是可以讓程式在後臺較長久的執行。在沒有使用GCD時,當app被按home鍵退出後,app僅有最多5秒鐘的時候做一些儲存或清理資源的工作。但是在使用GCD後,app最多有10分鐘的時間在後臺長久執行。這個時間可以用來做清理本地快取,傳送統計資料等工作。

// AppDelegate.h檔案

@property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundUpdateTask;

// AppDelegate.m檔案

  • (void)applicationDidEnterBackground:(UIApplication *)application

{

[self beingBackgroundUpdateTask];

// 在這裡加上你需要長久執行的程式碼

[self endBackgroundUpdateTask];

}

  • (void)beingBackgroundUpdateTask

{

self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{

    [self endBackgroundUpdateTask];

}];

}

  • (void)endBackgroundUpdateTask

{

[[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];

self.backgroundUpdateTask = UIBackgroundTaskInvalid;

}

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章