1 GCD栅栏函数
栅栏函数用户控制队列里异步函数的的执行顺序。
注:栅栏函数不能使用全局并发队列,需要用自己创建的并发队列。
- (void)barrier {
// 创建并发队列
dispatch_queue_t queue = dispatch_queue_create("com.zyx.barrier", 0);
// 创建人物,添加到队列
dispatch_async(queue, ^{
NSLog(@"download1-----");
});
dispatch_async(queue, ^{
NSLog(@"download2-----");
});
// 栅栏函数,用于控制先执行人物1和2 再执行任务3
dispatch_barrier_async(queue, ^{
NSLog(@"++++++++++++++++++++++");
});
dispatch_async(queue, ^{
NSLog(@"download3-----");
});
}
2 GCD快速迭代
开子线程和主线程一起完成遍历任务,任务的执行是并发的。
- (void)applyDemo {
/*
参数1:遍历次数
参数2:队列(并发队列)
参数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 获取目标文件路径
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队列组的使用
// 队列组
- (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-----");
});
// 拦截通知,当当队列里面的任务执行完毕后进入该方法,该方法不会阻塞
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();
// 该方法后面的异步任务会被纳入到队列组的监听范围中
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);
});
// 拦截通知,当当队列里面的任务执行完毕后进入该方法
dispatch_group_notify(group, queue, ^{
NSLog(@"task is over");
});
}
4 GCD异步函数方式2
- (void)asyncConcurrent {
/*
参数1:队列
参数2:参数3函数的参数
参数3:函数,用于封装任务
*/
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也能实现多线程编程 - NSOperation和NSOperationQueue实现多线程的具体步骤
1)先将需要执行的操作封装到一个NSOperation对象中
2)然后将NSOperation对象添加到NSOperationQueue中
3)系统会自动将NSOperationQueue中的NSOperation取出来
4)将取出的NSOperation封装的操作放到一条新的线程中执行
6.2 NSOperation的子类
- NSOperation是个抽象类,并不具备封装操作的能力,必须要使用它的子类
- 使用NSOperation紫烈的方式有3种
1)NSInvocationOperation
2)NSBlockOperation
3)自定义子类集成NSOperation,实现内部相应的方法
- (void)invocationOperation { // 不会开启新的线程
/*
参数1:目标对象
参数2:执行的操作方法
参数3:方法的参数
*/
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操作里面的任务超过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 创建操作
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 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 3 将操作添加到队列
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
// 简便方法
[queue addOperationWithBlock:^{
NSLog(@"4--%@",[NSThread currentThread]);
}];
}
- (void)invocationOperationWithQueue {
// 1 创建操作
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 创建队列
/*
NSOperationQueue
主队列:和GCD主队列一样,也是串行队列 [NSOperationQueue mainQueue]
非主队列:[[NSOperationQueue alloc] init]
非主队列非常特殊,又分为串行队列和并发队列,默认是并发队列
*/
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 3 添加操作到队列中执行
[queue addOperation:op1]; // 内部已经调用的start方法
[queue addOperation:op2];
[queue addOperation:op3];
}
8 自定义NSOperation
- (void)customOperationWithQueue {
// 创建操作
ZYXOperation *op1 = [[ZYXOperation alloc] init];
// 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 添加操作到队列
[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 { // 自定义操作需要实现该方法,明确要执行什么操作
NSLog(@"main---%@",[NSThread currentThread]);
}
@end
9 NSOperation的其他用法
9.1 如何设置串行队列
- (void)test {
// 1 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 默认是并发队列
// maxConcurrentOperationCount 最大执行并发操作数量
// maxConcurrentOperationCount默认值为-1 表示不受限制
// maxConcurrentOperationCount = 0 不会执行操作
// maxConcurrentOperationCount = 1 串行队列
// maxConcurrentOperationCount >= 2 并发队列
queue.maxConcurrentOperationCount = 1;
// 2 创建操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1--%@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2--%@",[NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"3--%@",[NSThread currentThread]);
}];
// 添加操作到队列
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
}
9.2 队列任务的开始、暂停、继续以及取消操作
- (IBAction)startOperation:(UIButton *)sender {
[self test];
}
// 暂停任务
- (IBAction)pauseOperation:(UIButton *)sender {
// 暂停是可以恢复的
// 队列中的任务也是有状态的:已执行、正在执行、未执行
// 不能取消队列里面正在执行的任务
[self.queue setSuspended:YES];
}
// 继续任务
- (IBAction)restartOperation:(UIButton *)sender {
[self.queue setSuspended:NO];
}
// 取消任务
- (IBAction)cancelOperation:(UIButton *)sender {
// 取消是不可以恢复的
[self.queue cancelAllOperations];
}
- (void)test {
// 1 创建队列
self.queue = [[NSOperationQueue alloc] init]; // 默认是并发队列
// maxConcurrentOperationCount 最大执行并发操作数量
// maxConcurrentOperationCount默认值为-1 表示不受限制
// maxConcurrentOperationCount = 0 不会执行操作
// maxConcurrentOperationCount = 1 串行队列
// maxConcurrentOperationCount >= 2 并发队列
self.queue.maxConcurrentOperationCount = 1;
// 2 创建操作
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]);
}
}];
// 添加操作到队列
[self.queue addOperation:op1];
[self.queue addOperation:op2];
[self.queue addOperation:op3];
}
9.3 自定义NSOperation的取消操作
- (IBAction)startOperation:(UIButton *)sender {
// 1 创建自定义操作
ZYXOperation *op1 = [[ZYXOperation alloc] init];
// 2 创建队列
self.queue = [[NSOperationQueue alloc] init];
// 3 添加操作到队列
[self.queue addOperation:op1];
}
// 暂停任务
- (IBAction)pauseOperation:(UIButton *)sender {
// 暂停是可以恢复的
// 队列中的任务也是有状态的:已执行、正在执行、未执行
// 不能取消队列里面正在执行的任务
[self.queue setSuspended:YES];
}
// 继续任务
- (IBAction)restartOperation:(UIButton *)sender {
[self.queue setSuspended:NO];
}
// 取消任务
- (IBAction)cancelOperation:(UIButton *)sender {
// 取消是不可以恢复的
[self.queue cancelAllOperations];
}
- (void)main {
for (int i = 0; i < 10000; i++) {
NSLog(@"1--%d---%@",i,[NSThread currentThread]);
}
// 官方推荐方式,也可以放在循环里面,但这样会消耗性能
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操作依赖和监听
10.1 操作依赖和监听
- (void)operationDepency {
// 1 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSOperationQueue *queue2 = [[NSOperationQueue alloc] init];
// 2 创建操作
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]);
};
// 添加操作依赖 不仅同一个队列可以,而且不同队列之间亦可以
// 注意:不能添加循环依赖,这样会导致不会执行任何操作 依赖可以跨队列
[op1 addDependency:op2];
[op2 addDependency:op3];
// 添加操作到队列
[queue addOperation:op1];
[queue addOperation:op2];
[queue2 addOperation:op3];
}
11 NSOperation实现线程间通信
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 {
// 创建队列
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();
// 关闭上下文
UIGraphicsEndImageContext();
//更新UI
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}];
}];
// 添加依赖
[op3 addDependency:op1];
[op3 addDependency:op2];
// 添加操作到队列
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
}
12 多线程补充
12.1 在使用NSOperation和NSOperationQueue时,将操作添加到队列时,会自动条用operation的start方法。而在调用start方法时,会去调用main方法。
12.2 在使用NSThread时,初始化时,可以直接使用init
进行初始化,然后再其main方法里面添加任务。
- (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
网友评论