1 GCD柵欄函數(shù)
柵欄函數(shù)用戶控制隊(duì)列里異步函數(shù)的的執(zhí)行順序澳窑。
注:柵欄函數(shù)不能使用全局并發(fā)隊(duì)列斧散,需要用自己創(chuàng)建的并發(fā)隊(duì)列。
- (void)barrier {
// 創(chuàng)建并發(fā)隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("com.zyx.barrier", 0);
// 創(chuàng)建人物照捡,添加到隊(duì)列
dispatch_async(queue, ^{
NSLog(@"download1-----");
});
dispatch_async(queue, ^{
NSLog(@"download2-----");
});
// 柵欄函數(shù)颅湘,用于控制先執(zhí)行人物1和2 再執(zhí)行任務(wù)3
dispatch_barrier_async(queue, ^{
NSLog(@"++++++++++++++++++++++");
});
dispatch_async(queue, ^{
NSLog(@"download3-----");
});
}
2 GCD快速迭代
開子線程和主線程一起完成遍歷任務(wù),任務(wù)的執(zhí)行是并發(fā)的栗精。
- (void)applyDemo {
/*
參數(shù)1:遍歷次數(shù)
參數(shù)2:隊(duì)列(并發(fā)隊(duì)列)
參數(shù)3:索引
*/
dispatch_apply(20, dispatch_get_global_queue(0, 0), ^(size_t index) {
NSLog(@"%zd---%@",index,[NSThread currentThread]);
});
}
// 文件剪切操作
- (void)moveFile {
// 1 拿到要移動文件路徑
NSString *from = @"/Users/apple/Desktop/from";
// 2 獲取目標(biāo)文件路徑
NSString *to = @"/Users/apple/Desktop/to";
// 3 得到目錄下所有文件
NSArray *filePath = [[NSFileManager defaultManager] subpathsAtPath:from];
NSLog(@"%@",filePath);
// 4 移動文件到指定目錄
NSInteger count = filePath.count;
dispatch_apply(count, dispatch_get_global_queue(0, 0), ^(size_t index) {
// 4.1 拼接文件全路徑
NSString *fullPath = [from stringByAppendingPathComponent:filePath[index]];
NSString *toFullPath = [to stringByAppendingPathComponent:filePath[index]];
NSError *error;
[[NSFileManager defaultManager] moveItemAtPath:fullPath toPath:toFullPath error:&error];
});
}
3 GCD隊(duì)列組的使用
// 隊(duì)列組
- (void)group1 {
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
NSLog(@"download1-----");
});
dispatch_group_async(group, queue, ^{
NSLog(@"download2-----");
});
dispatch_group_async(group, queue, ^{
NSLog(@"download3-----");
});
// 攔截通知,當(dāng)當(dāng)隊(duì)列里面的任務(wù)執(zhí)行完畢后進(jìn)入該方法,該方法不會阻塞
dispatch_group_notify(group, queue, ^{
NSLog(@"task is over");
});
// 該方法是阻塞的
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"---end---");
}
- (void)group2 {
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_t group = dispatch_group_create();
// 該方法后面的異步任務(wù)會被納入到隊(duì)列組的監(jiān)聽范圍中
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
NSLog(@"download1-----");
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
NSLog(@"download2-----");
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
NSLog(@"download3-----");
dispatch_group_leave(group);
});
// 攔截通知悲立,當(dāng)當(dāng)隊(duì)列里面的任務(wù)執(zhí)行完畢后進(jìn)入該方法
dispatch_group_notify(group, queue, ^{
NSLog(@"task is over");
});
}
4 GCD異步函數(shù)方式2
- (void)asyncConcurrent {
/*
參數(shù)1:隊(duì)列
參數(shù)2:參數(shù)3函數(shù)的參數(shù)
參數(shù)3:函數(shù)鹿寨,用于封裝任務(wù)
*/
dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
dispatch_async_f(dispatch_get_global_queue(0, 0), NULL, task);
}
void (task)(void *params) {
NSLog(@"--%s--",__func__);
}
5 單例模式通用宏
#define SingleH(name) + (instancetype)share##name;
#if __has_feature(objc_arc) // ARC模式
#define SinglM(name) static id _instance;\
+ (instancetype)allocWithZone:(struct _NSZone *)zone { \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [super allocWithZone:zone]; \
}); \
return _instance; \
} \
\
+ (instancetype)share##name { \
return [[self alloc] init]; \
} \
\
- (id)copyWithZone:(NSZone *)zone { \
return _instance; \
} \
\
- (id)mutableCopyWithZone:(NSZone *)zone { \
return _instance; \
}
#else // MRC模式
#define SinglM(name) static id _instance;\
+ (instancetype)allocWithZone:(struct _NSZone *)zone { \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [super allocWithZone:zone]; \
}); \
return _instance; \
} \
\
+ (instancetype)share##name { \
return [[self alloc] init]; \
} \
\
- (id)copyWithZone:(NSZone *)zone { \
return _instance; \
} \
\
- (id)mutableCopyWithZone:(NSZone *)zone { \
return _instance; \
} \
- (oneway void)release { \
\
} \
\
- (instancetype)retain { \
return _instance; \
} \
\
- (NSUInteger)retainCount { \
return MAXFLOAT; \
}
#endif
6 NSOperation基本概念
6.1 簡介
- NSOperation的作用
配合使用NSOperation和NSOperationQueue也能實(shí)現(xiàn)多線程編程 - NSOperation和NSOperationQueue實(shí)現(xiàn)多線程的具體步驟
1)先將需要執(zhí)行的操作封裝到一個NSOperation對象中
2)然后將NSOperation對象添加到NSOperationQueue中
3)系統(tǒng)會自動將NSOperationQueue中的NSOperation取出來
4)將取出的NSOperation封裝的操作放到一條新的線程中執(zhí)行
6.2 NSOperation的子類
- NSOperation是個抽象類,并不具備封裝操作的能力薪夕,必須要使用它的子類
- 使用NSOperation紫烈的方式有3種
1)NSInvocationOperation
2)NSBlockOperation
3)自定義子類集成NSOperation脚草,實(shí)現(xiàn)內(nèi)部相應(yīng)的方法
- (void)invocationOperation { // 不會開啟新的線程
/*
參數(shù)1:目標(biāo)對象
參數(shù)2:執(zhí)行的操作方法
參數(shù)3:方法的參數(shù)
*/
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil];
[op1 start];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil];
[op2 start];
NSInvocationOperation *op3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil];
[op3 start];
}
- (void)download1 {
NSLog(@"%s--%@",__func__,[NSThread currentThread]);
}
- (void)blockOperation {
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1--%@",[NSThread currentThread]);
}];
[op1 start];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1--%@",[NSThread currentThread]);
}];
[op2 start];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1--%@",[NSThread currentThread]);
}];
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1--%@",[NSThread currentThread]);
}];
[op4 start];
NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1--%@",[NSThread currentThread]);
}];
[op5 start];
NSBlockOperation *op6 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1--%@",[NSThread currentThread]);
}];
[op6 start];
// 如果block操作里面的任務(wù)超過1個,那么會開啟多個線程原献,但不一定是子線程
[op3 addExecutionBlock:^{
NSLog(@"4--%@",[NSThread currentThread]);
}];
[op3 addExecutionBlock:^{
NSLog(@"5--%@",[NSThread currentThread]);
}];
[op3 addExecutionBlock:^{
NSLog(@"6--%@",[NSThread currentThread]);
}];
[op3 start];
}
7 NSOperationQueue的基本使用
- (void)blockOperationWithQueue {
// 1 創(chuàng)建操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1--%@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2--%@",[NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"3--%@",[NSThread currentThread]);
}];
// 2 創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 3 將操作添加到隊(duì)列
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
// 簡便方法
[queue addOperationWithBlock:^{
NSLog(@"4--%@",[NSThread currentThread]);
}];
}
- (void)invocationOperationWithQueue {
// 1 創(chuàng)建操作
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil];
NSInvocationOperation *op3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil];
// 2 創(chuàng)建隊(duì)列
/*
NSOperationQueue
主隊(duì)列:和GCD主隊(duì)列一樣馏慨,也是串行隊(duì)列 [NSOperationQueue mainQueue]
非主隊(duì)列:[[NSOperationQueue alloc] init]
非主隊(duì)列非常特殊,又分為串行隊(duì)列和并發(fā)隊(duì)列姑隅,默認(rèn)是并發(fā)隊(duì)列
*/
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 3 添加操作到隊(duì)列中執(zhí)行
[queue addOperation:op1]; // 內(nèi)部已經(jīng)調(diào)用的start方法
[queue addOperation:op2];
[queue addOperation:op3];
}
8 自定義NSOperation
- (void)customOperationWithQueue {
// 創(chuàng)建操作
ZYXOperation *op1 = [[ZYXOperation alloc] init];
// 創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 添加操作到隊(duì)列
[queue addOperation:op1];
}
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface ZYXOperation : NSOperation
@end
NS_ASSUME_NONNULL_END
#import "ZYXOperation.h"
@implementation ZYXOperation
- (void)main { // 自定義操作需要實(shí)現(xiàn)該方法写隶,明確要執(zhí)行什么操作
NSLog(@"main---%@",[NSThread currentThread]);
}
@end
9 NSOperation的其他用法
9.1 如何設(shè)置串行隊(duì)列
- (void)test {
// 1 創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 默認(rèn)是并發(fā)隊(duì)列
// maxConcurrentOperationCount 最大執(zhí)行并發(fā)操作數(shù)量
// maxConcurrentOperationCount默認(rèn)值為-1 表示不受限制
// maxConcurrentOperationCount = 0 不會執(zhí)行操作
// maxConcurrentOperationCount = 1 串行隊(duì)列
// maxConcurrentOperationCount >= 2 并發(fā)隊(duì)列
queue.maxConcurrentOperationCount = 1;
// 2 創(chuàng)建操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1--%@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2--%@",[NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"3--%@",[NSThread currentThread]);
}];
// 添加操作到隊(duì)列
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
}
9.2 隊(duì)列任務(wù)的開始、暫停讲仰、繼續(xù)以及取消操作
- (IBAction)startOperation:(UIButton *)sender {
[self test];
}
// 暫停任務(wù)
- (IBAction)pauseOperation:(UIButton *)sender {
// 暫停是可以恢復(fù)的
// 隊(duì)列中的任務(wù)也是有狀態(tài)的:已執(zhí)行慕趴、正在執(zhí)行、未執(zhí)行
// 不能取消隊(duì)列里面正在執(zhí)行的任務(wù)
[self.queue setSuspended:YES];
}
// 繼續(xù)任務(wù)
- (IBAction)restartOperation:(UIButton *)sender {
[self.queue setSuspended:NO];
}
// 取消任務(wù)
- (IBAction)cancelOperation:(UIButton *)sender {
// 取消是不可以恢復(fù)的
[self.queue cancelAllOperations];
}
- (void)test {
// 1 創(chuàng)建隊(duì)列
self.queue = [[NSOperationQueue alloc] init]; // 默認(rèn)是并發(fā)隊(duì)列
// maxConcurrentOperationCount 最大執(zhí)行并發(fā)操作數(shù)量
// maxConcurrentOperationCount默認(rèn)值為-1 表示不受限制
// maxConcurrentOperationCount = 0 不會執(zhí)行操作
// maxConcurrentOperationCount = 1 串行隊(duì)列
// maxConcurrentOperationCount >= 2 并發(fā)隊(duì)列
self.queue.maxConcurrentOperationCount = 1;
// 2 創(chuàng)建操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 10000; i++) {
NSLog(@"1--%d--%@",i,[NSThread currentThread]);
}
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 10000; i++) {
NSLog(@"2--%d--%@",i,[NSThread currentThread]);
}
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 10000; i++) {
NSLog(@"3--%d--%@",i,[NSThread currentThread]);
}
}];
// 添加操作到隊(duì)列
[self.queue addOperation:op1];
[self.queue addOperation:op2];
[self.queue addOperation:op3];
}
9.3 自定義NSOperation的取消操作
- (IBAction)startOperation:(UIButton *)sender {
// 1 創(chuàng)建自定義操作
ZYXOperation *op1 = [[ZYXOperation alloc] init];
// 2 創(chuàng)建隊(duì)列
self.queue = [[NSOperationQueue alloc] init];
// 3 添加操作到隊(duì)列
[self.queue addOperation:op1];
}
// 暫停任務(wù)
- (IBAction)pauseOperation:(UIButton *)sender {
// 暫停是可以恢復(fù)的
// 隊(duì)列中的任務(wù)也是有狀態(tài)的:已執(zhí)行鄙陡、正在執(zhí)行冕房、未執(zhí)行
// 不能取消隊(duì)列里面正在執(zhí)行的任務(wù)
[self.queue setSuspended:YES];
}
// 繼續(xù)任務(wù)
- (IBAction)restartOperation:(UIButton *)sender {
[self.queue setSuspended:NO];
}
// 取消任務(wù)
- (IBAction)cancelOperation:(UIButton *)sender {
// 取消是不可以恢復(fù)的
[self.queue cancelAllOperations];
}
- (void)main {
for (int i = 0; i < 10000; i++) {
NSLog(@"1--%d---%@",i,[NSThread currentThread]);
}
// 官方推薦方式,也可以放在循環(huán)里面趁矾,但這樣會消耗性能
if (self.isCancelled) {
return;
}
for (int i = 0; i < 10000; i++) {
NSLog(@"2--%d---%@",i,[NSThread currentThread]);
}
if (self.isCancelled) {
return;
}
for (int i = 0; i < 10000; i++) {
NSLog(@"3--%d---%@",i,[NSThread currentThread]);
}
}
10 NSOperation操作依賴和監(jiān)聽
10.1 操作依賴和監(jiān)聽
- (void)operationDepency {
// 1 創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSOperationQueue *queue2 = [[NSOperationQueue alloc] init];
// 2 創(chuàng)建操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1--%@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2--%@",[NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"3--%@",[NSThread currentThread]);
}];
// 操作依賴
op3.completionBlock = ^{
NSLog(@"task is over--%@",[NSThread currentThread]);
};
// 添加操作依賴 不僅同一個隊(duì)列可以耙册,而且不同隊(duì)列之間亦可以
// 注意:不能添加循環(huán)依賴,這樣會導(dǎo)致不會執(zhí)行任何操作 依賴可以跨隊(duì)列
[op1 addDependency:op2];
[op2 addDependency:op3];
// 添加操作到隊(duì)列
[queue addOperation:op1];
[queue addOperation:op2];
[queue2 addOperation:op3];
}
11 NSOperation實(shí)現(xiàn)線程間通信
11.1 下載圖片demo
- (void)downloadImage {
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSString *str = @"http://cdn.duitang.com/uploads/item/201504/19/20150419H4413_XdNfU.thumb.700_0.png";
NSURL *url = [NSURL URLWithString:str];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
//更新UI
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}];
}];
[queue addOperation:op1];
}
11.2 下載并合成圖片
- (void)downloadCombineImage {
// 創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
__block UIImage *image1;
__block UIImage *image2;
// 下載圖片1
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSString *str = @"http://cdn.duitang.com/uploads/item/201504/19/20150419H4413_XdNfU.thumb.700_0.png";
NSURL *url = [NSURL URLWithString:str];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
image1 = [UIImage imageWithData:data];
}];
// 下載圖片2
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSString *str = @"http://5b0988e595225.cdn.sohucs.com/images/20171210/362dcd1c009842ff99b33f5d51bbfb80.jpeg";
NSURL *url = [NSURL URLWithString:str];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
image2 = [UIImage imageWithData:data];
}];
// 合成圖片
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
// 獲取上下文
UIGraphicsBeginImageContext(CGSizeMake(200, 200));
// 畫image1
[image1 drawInRect:CGRectMake(0, 0, 100, 200)];
// 畫image2
[image2 drawInRect:CGRectMake(100, 0, 100, 200)];
// 獲取圖片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 關(guān)閉上下文
UIGraphicsEndImageContext();
//更新UI
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}];
}];
// 添加依賴
[op3 addDependency:op1];
[op3 addDependency:op2];
// 添加操作到隊(duì)列
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
}
12 多線程補(bǔ)充
12.1 在使用NSOperation和NSOperationQueue時毫捣,將操作添加到隊(duì)列時觅玻,會自動條用operation的start方法。而在調(diào)用start方法時培漏,會去調(diào)用main方法溪厘。
12.2 在使用NSThread時,初始化時牌柄,可以直接使用init
進(jìn)行初始化畸悬,然后再其main方法里面添加任務(wù)。
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self customThread2];
}
- (void)customThread {
ZYXOperation *op1 = [[ZYXOperation alloc] init];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:op1];
}
- (void)customThread2 {
ZYXThread *op1 = [[ZYXThread alloc] init];
[op1 start];
}
#import "ZYXOperation.h"
@implementation ZYXOperation
- (void)start {
NSLog(@"start--start");
[super start];
NSLog(@"start--end");
}
- (void)main {
NSLog(@"main--start");
[super main];
NSLog(@"main--end");
}
@end
#import "ZYXThread.h"
@implementation ZYXThread
- (void)main {
NSLog(@"%s---%@",__func__,[NSThread currentThread]);
}
@end