美文网首页
多线程网络02

多线程网络02

作者: 努力爬行中的蜗牛 | 来源:发表于2019-12-11 19:45 被阅读0次
    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
    

    相关文章

      网友评论

          本文标题:多线程网络02

          本文链接:https://www.haomeiwen.com/subject/mnxogctx.html