iOS常見的延遲執行有2種方式網絡
(1)調用NSObject的方法 併發
[self performSelector"@selector(run) withObject:nil afterDelay:2.0];異步
//2秒後再調用self的run 方法async
(2)GCD函數
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int16_t)(2.0*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//2秒後異步執行這裏的代碼
});函數
2.說明
第一種方法,該方法在那個線程調用,那麼run就在哪一個線程執行(當前線程),一般是主線程。 url
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"打印線程----%@",[NSThread currentThread]);
//延遲執行
//第一種方法:延遲3秒鐘調用run函數
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
}
-(void)run
{
NSLog(@"延遲執行----%@",[NSThread currentThread]);
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//在異步函數中執行
dispatch_queue_t queue = dispatch_queue_create("wendingding", 0);
dispatch_sync(queue, ^{
[self performSelector:@selector(test) withObject:nil afterDelay:1.0];
});
NSLog(@"異步函數");
}
-(void)test
{
NSLog(@"異步函數中延遲執行----%@",[NSThread currentThread]);
}
@end
spa
說明:若是把該方法放在異步函數中執行,則方法不會被調用(BUG?)線程
第二種方法3d
- (void)viewDidLoad { [super viewDidLoad]; NSLog(@"打印當前線程---%@", [NSThread currentThread]); //延遲執行,第二種方式 //能夠安排其線程(1),主隊列 dispatch_queue_t queue= dispatch_get_main_queue(); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), queue, ^{ NSLog(@"主隊列--延遲執行------%@",[NSThread currentThread]); }); //能夠安排其線程(2),併發隊列 //1.獲取全局併發隊列 dispatch_queue_t queue1= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //2.計算任務執行的時間 dispatch_time_t when=dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)); //3.會在when這個時間點,執行queue中的這個任務 dispatch_after(when, queue1, ^{ NSLog(@"併發隊列-延遲執行------%@",[NSThread currentThread]); }); } @end
延遲執行:不須要再寫方法,且它還傳遞了一個隊列,咱們能夠指定並安排其線程。 code
若是隊列是主隊列,那麼就在主線程執行,若是隊列是併發隊列,那麼會新開啓一個線程,在子線程中執行。
//-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event //{ // if (_log==NO) { // NSLog(@"該行代碼只執行一次"); // _log=YES; // } //} -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"該行代碼只執行一次"); }); }
1.註釋中方法缺點,這是一個對象方法,當又建立了一個新的控制器,打印代碼仍是會執行(或者把狀態開關做爲本地存儲,略繁瑣,不推薦)
2.使用dispatch_once 一次性代碼
需求:從網絡上下載2個圖片,把2張圖片合併成1張最終顯示再view上
#import "ViewController.h" //宏定義全局併發隊列 #define global_quque dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) //宏定義主隊列 #define main_queue dispatch_get_main_queue() @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; _imageView1 = [[UIImageView alloc]initWithFrame:CGRectMake(0, 100, 100, 100)]; [self.view addSubview:_imageView1]; _imageView2 = [[UIImageView alloc]initWithFrame:CGRectMake(105, 100, 100, 100)]; [self.view addSubview:_imageView2]; _imageView3 = [[UIImageView alloc]initWithFrame:CGRectMake(0, 200, 200, 100)]; [self.view addSubview:_imageView3]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { dispatch_async(global_quque, ^{ UIImage *image1 = [self imageWithUrl:@"http://d.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=2b9a12172df5e0fefa1581533d095fcd/cefc1e178a82b9019115de3d738da9773912ef00.jpg"]; NSLog(@"圖片1下載完成---%@",[NSThread currentThread]); NSLog(@"_imageView1下載完成---%@",[NSThread currentThread]); UIImage *image2 = [self imageWithUrl:@"http://h.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=f47fd63ca41ea8d39e2f7c56f6635b2b/1e30e924b899a9018b8d3ab11f950a7b0308f5f9.jpg"]; NSLog(@"圖片2下載完成---%@",[NSThread currentThread]); NSLog(@"_imageView2下載完成---%@",[NSThread currentThread]); dispatch_async(main_queue, ^{ _imageView1.image =image1; _imageView2.image =image2; NSLog(@"顯示圖片---%@",[NSThread currentThread]); UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 100), NO, 1); [image1 drawInRect:CGRectMake(0, 0, 100, 100)]; [image2 drawInRect:CGRectMake(100, 0, 100, 100)]; _imageView3.image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); NSLog(@"圖片合併完成---%@",[NSThread currentThread]); }); }); } //封裝一個方法,傳入一個url參數,返回一張網絡上下載的圖片 -(UIImage *)imageWithUrl:(NSString *)urlStr { NSURL *url=[NSURL URLWithString:urlStr]; NSData *urlData = [NSData dataWithContentsOfURL:url]; UIImage *image = [UIImage imageWithData:urlData]; return image; }
問題:這種方式效率不高,要等到圖片下載完成以後 才行.
提示:使用隊列組能夠讓圖片1和圖片2的下載任務同時進行,且當兩個下載任務都完成的時候回到主線程進行顯示。
使用組隊來解決 (適用於2個耗時的操做,最後再回到主線程去執行)
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { //1.建立一個隊列組 dispatch_group_t group =dispatch_group_create(); //2.開啓一個任務下載圖片1 __block UIImage *image1=nil; dispatch_group_async(group, global_quque, ^{ image1 = [self imageWithUrl:@"http://d.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=2b9a12172df5e0fefa1581533d095fcd/cefc1e178a82b9019115de3d738da9773912ef00.jpg"]; NSLog(@"圖片1下載完成---%@",[NSThread currentThread]); }); //3.開啓一個任務下載圖片2 __block UIImage *image2=nil; dispatch_group_async(group, global_quque, ^{ image2 = [self imageWithUrl:@"http://h.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=f47fd63ca41ea8d39e2f7c56f6635b2b/1e30e924b899a9018b8d3ab11f950a7b0308f5f9.jpg"]; NSLog(@"圖片2下載完成---%@",[NSThread currentThread]); }); //同時執行下載圖片1\下載圖片2操做 //4.等group中的全部任務都執行完畢, 再回到主線程執行其餘操做 dispatch_group_notify(group, main_queue, ^{ NSLog(@"顯示圖片---%@",[NSThread currentThread]); _imageView1.image = image1; _imageView2.image=image2; //合併兩張圖片,最後一個參數是浮點數(0.0),不要寫成0。 UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 100), NO, 1); [image1 drawInRect:CGRectMake(0, 0, 100, 100)]; [image2 drawInRect:CGRectMake(100, 0, 100, 100)]; _imageView3.image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); NSLog(@"圖片合併完成---%@",[NSThread currentThread]); }); }