一、延遲執(zhí)行
1.介紹
iOS常見的延時(shí)執(zhí)行有2種方式
(1)調(diào)用NSObject的方法
[self?performSelector:@selector(run)?withObject:nil?afterDelay:2.0];
// 2秒后再調(diào)用self的run方法
(2)使用GCD函數(shù)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0?*?NSEC_PER_SEC)),?dispatch_get_main_queue(), ^{
// 2秒后異步執(zhí)行這里的代碼...
});
2.說明
第一種方法中剩,該方法在那個(gè)線程調(diào)用,那么run就在哪個(gè)線程執(zhí)行(當(dāng)前線程)悦施,通常是主線程煌珊。
[self?performSelector:@selector(run)?withObject:nil?afterDelay:3.0];
說明:在3秒鐘之后,執(zhí)行run函數(shù)
代碼示例:
//
//? YYViewController.m
//? 01-GCD的常見使用(延遲執(zhí)行)
//
//? Created by apple on 14-6-25.
//? Copyright (c) 2014年 itcase. All rights reserved.
//
#import "YYViewController.h"
@interface YYViewController ()
@end
@implementation YYViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"打印線程----%@",[NSThread currentThread]);
//延遲執(zhí)行
//第一種方法:延遲3秒鐘調(diào)用run函數(shù)
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
}
-(void)run
{
NSLog(@"延遲執(zhí)行----%@",[NSThread currentThread]);
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//在異步函數(shù)中執(zhí)行
dispatch_queue_t queue = dispatch_queue_create("wendingding", 0);
dispatch_sync(queue, ^{
[self performSelector:@selector(test) withObject:nil afterDelay:1.0];
});
NSLog(@"異步函數(shù)");
}
-(void)test
{
NSLog(@"異步函數(shù)中延遲執(zhí)行----%@",[NSThread currentThread]);
}
@end
說明:如果把該方法放在異步函數(shù)中執(zhí)行邪乍,則方法不會(huì)被調(diào)用(BUG?)
第二種方法宪巨,
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//延遲執(zhí)行的方法
});
說明:在5秒鐘之后磷杏,執(zhí)行block中的代碼段。
參數(shù)說明:
什么時(shí)間捏卓,執(zhí)行這個(gè)隊(duì)列中的這個(gè)任務(wù)极祸。
代碼示例:
//
//? YYViewController.m
//? 02-GCD常見使用(延遲執(zhí)行2)
//
//? Created by apple on 14-6-25.
//? Copyright (c) 2014年 itcase. All rights reserved.
//
#import "YYViewController.h"
@interface YYViewController ()
@end
@implementation YYViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"打印當(dāng)前線程---%@",? [NSThread currentThread]);
//延遲執(zhí)行,第二種方式
//可以安排其線程(1),主隊(duì)列
dispatch_queue_t queue= dispatch_get_main_queue();
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), queue, ^{
NSLog(@"主隊(duì)列--延遲執(zhí)行------%@",[NSThread currentThread]);
});
//可以安排其線程(2),并發(fā)隊(duì)列
//1.獲取全局并發(fā)隊(duì)列
dispatch_queue_t queue1= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//2.計(jì)算任務(wù)執(zhí)行的時(shí)間
dispatch_time_t when=dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC));
//3.會(huì)在when這個(gè)時(shí)間點(diǎn)怠晴,執(zhí)行queue中的這個(gè)任務(wù)
dispatch_after(when, queue1, ^{
NSLog(@"并發(fā)隊(duì)列-延遲執(zhí)行------%@",[NSThread currentThread]);
});
}
@end
延遲執(zhí)行:不需要再寫方法贿肩,且它還傳遞了一個(gè)隊(duì)列,我們可以指定并安排其線程龄寞。
如果隊(duì)列是主隊(duì)列汰规,那么就在主線程執(zhí)行,如果隊(duì)列是并發(fā)隊(duì)列物邑,那么會(huì)新開啟一個(gè)線程溜哮,在子線程中執(zhí)行滔金。
二、一次性代碼
1.實(shí)現(xiàn)一次性代碼
需求:點(diǎn)擊控制器只有第一次點(diǎn)擊的時(shí)候才打印茂嗓。
實(shí)現(xiàn)代碼:
//
//? YYViewController.m
//? 03-GCD常見使用(一次性代碼)
//
//? Created by apple on 14-6-25.
//? Copyright (c) 2014年 itcase. All rights reserved.
//
#import "YYViewController.h"
@interface YYViewController ()
@property(nonatomic,assign) BOOL log;
@end
@implementation YYViewController
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (_log==NO) {
NSLog(@"該行代碼只執(zhí)行一次");
_log=YES;
}
}
@end
缺點(diǎn):這是一個(gè)對象方法餐茵,如果又創(chuàng)建一個(gè)新的控制器,那么打印代碼又會(huì)執(zhí)行述吸,因?yàn)槊總€(gè)新創(chuàng)建的控制器都有自己的布爾類型忿族,且新創(chuàng)建的默認(rèn)為NO,因此不能保證改行代碼在整個(gè)程序中只打印一次蝌矛。
2.使用dispatch_once一次性代碼
使用dispatch_once函數(shù)能保證某段代碼在程序運(yùn)行過程中只被執(zhí)行1次
static?dispatch_once_t?onceToken;
dispatch_once(&onceToken, ^{
//?只執(zhí)行1次的代碼(這里面默認(rèn)是線程安全的)
});
整個(gè)程序運(yùn)行過程中道批,只會(huì)執(zhí)行一次。
代碼示例:
//
//? YYViewController.m
//? 03-GCD常見使用(一次性代碼)
//
//? Created by apple on 14-6-25.
//? Copyright (c) 2014年 itcase. All rights reserved.
//
#import "YYViewController.h"
@interface YYViewController ()
@property(nonatomic,assign) BOOL log;
@end
@implementation YYViewController
//-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
//{
//? ? if (_log==NO) {
//? ? ? ? NSLog(@"該行代碼只執(zhí)行一次");
//? ? ? ? _log=YES;
//? ? }
//}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"該行代碼只執(zhí)行一次");
});
}
@end
效果(程序運(yùn)行過程中入撒,打印代碼只會(huì)執(zhí)行一次):
三隆豹、隊(duì)列組
需求:從網(wǎng)絡(luò)上下載兩張圖片,把兩張圖片合并成一張最終顯示在view上茅逮。
1.第一種方法
代碼示例:
//
//? YYViewController.m
//? 04-GCD基本使用(隊(duì)列組下載圖片)
//
//? Created by apple on 14-6-25.
//? Copyright (c) 2014年 itcase. All rights reserved.
//
#import "YYViewController.h"
//宏定義全局并發(fā)隊(duì)列
#define global_quque? ? dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
//宏定義主隊(duì)列
#define main_queue? ? ? dispatch_get_main_queue()
@interface YYViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView1;
@property (weak, nonatomic) IBOutlet UIImageView *imageView2;
@property (weak, nonatomic) IBOutlet UIImageView *imageView3;
@end
@implementation YYViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//獲取全局并發(fā)隊(duì)列
//? ? dispatch_queue_t queue= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//獲取主隊(duì)列
//? ? dispatch_queue_t queue= dispatch_get_main_queue();
//? ? 圖片1:http://d.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=2b9a12172df5e0fefa1581533d095fcd/cefc1e178a82b9019115de3d738da9773912ef00.jpg
//? ? 圖片2:http://h.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=f47fd63ca41ea8d39e2f7c56f6635b2b/1e30e924b899a9018b8d3ab11f950a7b0308f5f9.jpg
dispatch_async(global_quque, ^{
//下載圖片1
UIImage *image1= [self imageWithUrl:@"http://d.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=2b9a12172df5e0fefa1581533d095fcd/cefc1e178a82b9019115de3d738da9773912ef00.jpg"];
NSLog(@"圖片1下載完成---%@",[NSThread currentThread]);
//下載圖片2
UIImage *image2= [self imageWithUrl:@"http://h.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=f47fd63ca41ea8d39e2f7c56f6635b2b/1e30e924b899a9018b8d3ab11f950a7b0308f5f9.jpg"];
NSLog(@"圖片2下載完成---%@",[NSThread currentThread]);
//回到主線程顯示圖片
dispatch_async(main_queue, ^{
NSLog(@"顯示圖片---%@",[NSThread currentThread]);
self.imageView1.image=image1;
self.imageView2.image=image2;
//合并兩張圖片
UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 100), NO, 0.0);
[image1 drawInRect:CGRectMake(0, 0, 100, 100)];
[image2 drawInRect:CGRectMake(100, 0, 100, 100)];
self.imageView3.image=UIGraphicsGetImageFromCurrentImageContext();
//關(guān)閉上下文
UIGraphicsEndImageContext();
NSLog(@"圖片合并完成---%@",[NSThread currentThread]);
});
//
});
}
//封裝一個(gè)方法璃赡,傳入一個(gè)url參數(shù),返回一張網(wǎng)絡(luò)上下載的圖片
-(UIImage *)imageWithUrl:(NSString *)urlStr
{
NSURL *url=[NSURL URLWithString:urlStr];
NSData *data=[NSData dataWithContentsOfURL:url];
UIImage *image=[UIImage imageWithData:data];
return image;
}
@end
顯示效果:
打印查看:
問題:這種方式的效率不高献雅,需要等到圖片1.圖片2都下載完成后才行碉考。
提示:使用隊(duì)列組可以讓圖片1和圖片2的下載任務(wù)同時(shí)進(jìn)行,且當(dāng)兩個(gè)下載任務(wù)都完成的時(shí)候回到主線程進(jìn)行顯示挺身。
2.使用隊(duì)列組解決
步驟:
創(chuàng)建一個(gè)組
開啟一個(gè)任務(wù)下載圖片1
開啟一個(gè)任務(wù)下載圖片2
同時(shí)執(zhí)行下載圖片1\下載圖片2操作
等group中的所有任務(wù)都執(zhí)行完畢, 再回到主線程執(zhí)行其他操作
代碼示例
//
//? YYViewController.m
//? 04-GCD基本使用(隊(duì)列組下載圖片)
//
//? Created by apple on 14-6-25.
//? Copyright (c) 2014年 itcase. All rights reserved.
//
#import "YYViewController.h"
//宏定義全局并發(fā)隊(duì)列
#define global_quque? ? dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
//宏定義主隊(duì)列
#define main_queue? ? ? dispatch_get_main_queue()
@interface YYViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView1;
@property (weak, nonatomic) IBOutlet UIImageView *imageView2;
@property (weak, nonatomic) IBOutlet UIImageView *imageView3;
@end
@implementation YYViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//? ? 圖片1:http://d.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=2b9a12172df5e0fefa1581533d095fcd/cefc1e178a82b9019115de3d738da9773912ef00.jpg
//? ? 圖片2:http://h.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=f47fd63ca41ea8d39e2f7c56f6635b2b/1e30e924b899a9018b8d3ab11f950a7b0308f5f9.jpg
//1.創(chuàng)建一個(gè)隊(duì)列組
dispatch_group_t group = dispatch_group_create();
//2.開啟一個(gè)任務(wù)下載圖片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.開啟一個(gè)任務(wù)下載圖片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]);
});
//同時(shí)執(zhí)行下載圖片1\下載圖片2操作
//4.等group中的所有任務(wù)都執(zhí)行完畢, 再回到主線程執(zhí)行其他操作
dispatch_group_notify(group,main_queue, ^{
NSLog(@"顯示圖片---%@",[NSThread currentThread]);
self.imageView1.image=image1;
self.imageView2.image=image2;
//合并兩張圖片
//注意最后一個(gè)參數(shù)是浮點(diǎn)數(shù)(0.0)豆励,不要寫成0。
UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 100), NO, 0.0);
[image1 drawInRect:CGRectMake(0, 0, 100, 100)];
[image2 drawInRect:CGRectMake(100, 0, 100, 100)];
self.imageView3.image=UIGraphicsGetImageFromCurrentImageContext();
//關(guān)閉上下文
UIGraphicsEndImageContext();
NSLog(@"圖片合并完成---%@",[NSThread currentThread]);
});
}
-(void)download2image
{
//獲取全局并發(fā)隊(duì)列
//? ? dispatch_queue_t queue= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//獲取主隊(duì)列
//? ? dispatch_queue_t queue= dispatch_get_main_queue();
dispatch_async(global_quque, ^{
//下載圖片1
UIImage *image1= [self imageWithUrl:@"http://news.baidu.com/z/resource/r/image/2014-06-22/2a1009253cf9fc7c97893a4f0fe3a7b1.jpg"];
NSLog(@"圖片1下載完成---%@",[NSThread currentThread]);
//下載圖片2
UIImage *image2= [self imageWithUrl:@"http://news.baidu.com/z/resource/r/image/2014-06-22/2a1009253cf9fc7c97893a4f0fe3a7b1.jpg"];
NSLog(@"圖片2下載完成---%@",[NSThread currentThread]);
//回到主線程顯示圖片
dispatch_async(main_queue, ^{
NSLog(@"顯示圖片---%@",[NSThread currentThread]);
self.imageView1.image=image1;
self.imageView2.image=image2;
//合并兩張圖片
UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 100), NO, 0.0);
[image1 drawInRect:CGRectMake(0, 0, 100, 100)];
[image2 drawInRect:CGRectMake(0, 0, 100, 100)];
self.imageView3.image=UIGraphicsGetImageFromCurrentImageContext();
//關(guān)閉上下文
UIGraphicsEndImageContext();
NSLog(@"圖片合并完成---%@",[NSThread currentThread]);
});
//
});
}
//封裝一個(gè)方法瞒渠,傳入一個(gè)url參數(shù),返回一張網(wǎng)絡(luò)上下載的圖片
-(UIImage *)imageWithUrl:(NSString *)urlStr
{
NSURL *url=[NSURL URLWithString:urlStr];
NSData *data=[NSData dataWithContentsOfURL:url];
UIImage *image=[UIImage imageWithData:data];
return image;
}
@end
打印查看(同時(shí)開啟了兩個(gè)子線程技扼,分別下載圖片):
2.補(bǔ)充說明
有這么1種需求:
首先:分別異步執(zhí)行2個(gè)耗時(shí)的操作
其次:等2個(gè)異步操作都執(zhí)行完畢后伍玖,再回到主線程執(zhí)行操作
如果想要快速高效地實(shí)現(xiàn)上述需求,可以考慮用隊(duì)列組
dispatch_group_t?group =??dispatch_group_create();
dispatch_group_async(group,?dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,?0), ^{
//?執(zhí)行1個(gè)耗時(shí)的異步操作
});
dispatch_group_async(group,?dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,?0), ^{
//?執(zhí)行1個(gè)耗時(shí)的異步操作
});
dispatch_group_notify(group,?dispatch_get_main_queue(), ^{
//?等前面的異步操作都執(zhí)行完畢后剿吻,回到主線程...
});