美文网首页
iOS-多线程(NSThread+GCD+NSOperation

iOS-多线程(NSThread+GCD+NSOperation

作者: fjytqiu | 来源:发表于2016-08-02 11:15 被阅读368次

    一、基本概念

    1. 进程:系统中正在运行的应用程序。每个程序都是相互独立的,并且运行在一块独有的受保护的内存中
    2. 线程:进程基本执行路径。一个进程想要执行任务,就必须通过线程来执行。单条的线程通过串行的方式执行任务,也就是说任务是一个一个按顺序的执行
    3. 多线程:开启多条线程,让任务并发执行。(原理:在同一时间内,CPU 只会处理一条线程,多线程并发执行其实是,cpu在不同的线程之间快速的切换处理,只要cpu切换的足够快,就会给人多线程并发执行任务的假象)
      补充:并行指的是任务一起执行,强调的是过程;并发指的是任务以一起执行的方式开始执行,强调的是任务开始执行的方式。

    二、多线程的优缺点

    优点
    1. 可提高程序的执行效率
    2. 可合理提高cpu和内存的利用率
    缺点
    1. 开启一条线程所占用的内存较大(主线程 1M ;子线程 512KB)
    2. 线程多时,cpu在在切换线程上的开销较大,影响性能
    3. 线程间的通讯和数据共享等会将大程序设计的复杂度

    三、多线程的实现方案

    1. NSThread

    此方案是经过苹果封装后完全面向对象的,可以直接拿到线程对象进行操作,很直观、便捷。但是缺点就是需手动管理线程生命周期,所以不经常使用
    1.1 创建(3种方式)

    //  1.手动启动线程,可拿到线程对象进行额外的设置
        NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(addThread:) object:@"hahaha"];
        [thread start];
        
        //  2.分离出子线程 - 自动启动线程
        [NSThread detachNewThreadSelector:@selector(addChildThread:) toTarget:self withObject:@"子线程"];
        
        //  3.后台线程 - 自动启动线程
        [self performSelectorInBackground:@selector(addBackgroundThread:) withObject:@"后台线程"];
    

    1.2 NSThread 常涉及到的方法

        [thread cancel];  //取消线程
        [NSThread exit];
        [NSThread sleepForTimeInterval:3.0];  //阻塞线程
        [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:3.0]];
        [NSThread currentThread];  //获取当前线程
        [NSThread mainThread];  //获取主线程
        [NSThread isMultiThreaded];  //是否是多线程,返回BOOL值
    

    1.3 线程间通信

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        //  创建子线程
        NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(addThread:) object:@"hahaha"];
        [thread start];
    }
    
    - (void)addThread:(NSString *)name {
        NSLog(@"%@",[NSThread currentThread]);
        
        //  在子线程中回到主线程的两种方式
        [self performSelectorOnMainThread:@selector(goBackMainThread:) withObject:@"main" waitUntilDone:YES];
        [self performSelector:@selector(goBackMainThread:) onThread:[NSThread mainThread] withObject:@"test" waitUntilDone:YES];
    }
    
    - (void)goBackMainThread:(NSString *)name {
        NSLog(@"%@",[NSThread currentThread]);
    }
    

    打印结果

    2016-08-01 14:20:30.253 demo[66988:3541822] <NSThread: 0x79e71ab0>{number = 2, name = (null)}
    2016-08-01 14:20:30.258 demo[66988:3541733] <NSThread: 0x79e72a30>{number = 1, name = main}
    2016-08-01 14:20:30.259 demo[66988:3541733] <NSThread: 0x79e72a30>{number = 1, name = main}
    

    1.4 线程安全
    当多个线程访问同一块资源时会发生数据安全问题,也称为线程同步 ,这时候就需要加互斥锁 @synchronized(self){}

    2. GCD

    苹果为多核并行运算开发的解决方案,它可以自动的利用cpu的内核,并且系统自动管理线程的生命周期
    开发者要做的是将任务添加到队列中,系统会自动将队列中的任务按FIFO的原则取出任务(FIFO:先进先出,后进后出,如果以并发方式执行任务,则先出的任务还没结束前下一个的任务可以出列)

    2.1 任务和队列的理解
    任务:决定能不能开启新线程,分同步和异步任务两种

    -同步:任务只能在当前的线程执行,不具备开启新线程的能力(同步任务比较霸道,必须在当前的分配任务执行完,才算把分配任务的任务结束,和后面说的死锁有关联)
    -异步:任务可以在其它线程中执行,具备有开启新线程的能力

        //  同步任务
        dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        });
        //  异步任务
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
        });
    
    队列:决定任务将以什么方式执行,分串行和并发队列两种

    -串行:任务将一个接一个的执行(一个任务执行完才开始下一个任务)
    -并发:多个任务可以并发(同时)执行,要在异步任务函数中才能有效

    队列的创建

    -串行:系统提供两种方式

        //  1.系统提供的主队列
        dispatch_queue_t mainQueue = dispatch_get_main_queue();
        //  2.创建新的串行队列(参数1:队列名字,apple推荐使用com.example.myQueue的规则来命名队列,用于debug的时候追踪队列以便于调试,可以为空;
        //    参数2:可以传人NULL或DISPATCH_QUEUE_SERIAL表示串行队列)
        dispatch_queue_t queue = dispatch_queue_create("com.hhh.eatShit", NULL);
    

    - 并发:系统提供两种方式

        //  1.系统提供的全局队列(参数1:队列的优先级;参数2:传0即可)
        dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        //  2.创建新的并发队列
        dispatch_queue_t queue = dispatch_queue_create("com.hhh.eatShit", DISPATCH_QUEUE_CONCURRENT);
    
    2.2 GCD使用方式(任务和队列的结合方式)
    1. 异步任务+并发队列:使用频率高,开启多线程并发的执行任务
    2. 异步任务+串行队列:使用频率高,开启一条新线程,串行执行任务
    3. 同步任务+并发队列:基本不用,不开线程在当前线程串行执行任务我
    4. 同步任务+串行队列:基本不用,不开线程在当前线程串行执行任务我
    5. 异步任务+主队列:不开线程,在主线程中串行执行任务我
    6. 同步任务+主队列:不开线程,在主线程中串行执行任务我(注意死锁)
      注意:在当前的串行队列中添加同步任务到当前队列会发生死锁
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        //  主队列是串行的,在主队里中往主队列添加同步任务,发生死锁,无法执行打印内容
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"快把我打印出来");
        });
    }
    
    2.3 🍐演示GCD的使用
    1. 异步任务+并发队列
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        //  由系统决定开几条线程
        dispatch_queue_t queue = dispatch_queue_create("com.demo.bingfa", DISPATCH_QUEUE_CONCURRENT);
        dispatch_async(queue, ^{
            NSLog(@"任务1---%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务2---%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务3---%@",[NSThread currentThread]);
        });
    }
    

    打印

    2016-08-01 17:27:01.793 demo[79533:3667100] 任务1---<NSThread: 0x79858c40>{number = 2, name = (null)}
    2016-08-01 17:27:01.793 demo[79533:3667104] 任务3---<NSThread: 0x7865da50>{number = 4, name = (null)}
    2016-08-01 17:27:01.794 demo[79533:3667103] 任务2---<NSThread: 0x79a5a540>{number = 3, name = (null)}
    

    2.异步任务+串行队列

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        //  只开一条新线程
        dispatch_queue_t queue = dispatch_queue_create("com.demo.chuanxing", NULL);
        dispatch_async(queue, ^{
            NSLog(@"任务1---%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务2---%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务3---%@",[NSThread currentThread]);
        });
    }
    

    打印

    2016-08-01 17:29:13.092 demo[79710:3669166] 任务1---<NSThread: 0x7a236720>{number = 2, name = (null)}
    2016-08-01 17:29:13.093 demo[79710:3669166] 任务2---<NSThread: 0x7a236720>{number = 2, name = (null)}
    2016-08-01 17:29:13.094 demo[79710:3669166] 任务3---<NSThread: 0x7a236720>{number = 2, name = (null)}
    

    3.同步任务+并发队列

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        //  不开新线程,当前是主线程,所以任务1、2、3在主线程中执行
        dispatch_queue_t queue = dispatch_get_main_queue();
        dispatch_async(queue, ^{
            NSLog(@"任务1---%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务2---%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务3---%@",[NSThread currentThread]);
        });
    }
    

    打印

    2016-08-01 17:57:04.133 demo[81692:3691446] 任务1---<NSThread: 0x7a2314b0>{number = 1, name = main}
    2016-08-01 17:57:04.134 demo[81692:3691446] 任务2---<NSThread: 0x7a2314b0>{number = 1, name = main}
    2016-08-01 17:57:04.134 demo[81692:3691446] 任务3---<NSThread: 0x7a2314b0>{number = 1, name = main}
    

    4.同步任务+串行队列

    - (void)viewDidLoad {
        [super viewDidLoad];
        dispatch_queue_t queue = dispatch_queue_create("com.demo.chuanxing", NULL);
        dispatch_async(queue, ^{
            NSLog(@"新开的子线程---%@",[NSThread currentThread]);
    
            //  在新开的子线程中,在queue队列中测试
            dispatch_queue_t queue1 = dispatch_queue_create("com.demo.chuanxing", NULL);
            dispatch_sync(queue1, ^{
                NSLog(@"任务1---%@",[NSThread currentThread]);
            });
            dispatch_sync(queue1, ^{
                NSLog(@"任务2---%@",[NSThread currentThread]);
            });
            dispatch_sync(queue1, ^{
                NSLog(@"任务3---%@",[NSThread currentThread]);
            });
        });
    }
    

    打印

    2016-08-01 17:53:10.405 demo[81376:3688029] 新开的子线程---<NSThread: 0x78e7fe80>{number = 2, name = (null)}
    2016-08-01 17:53:10.406 demo[81376:3688029] 任务1---<NSThread: 0x78e7fe80>{number = 2, name = (null)}
    2016-08-01 17:53:10.407 demo[81376:3688029] 任务2---<NSThread: 0x78e7fe80>{number = 2, name = (null)}
    2016-08-01 17:53:10.407 demo[81376:3688029] 任务3---<NSThread: 0x78e7fe80>{number = 2, name = (null)}
    

    5.异步任务+主队列(同3)
    6.同步任务+主队列(切记不能在主队列中使用这种方式)

    - (void)viewDidLoad {
        [super viewDidLoad];
        dispatch_queue_t queue = dispatch_queue_create("com.demo.chuanxing", NULL);
        dispatch_async(queue, ^{
            NSLog(@"新开的子线程---%@",[NSThread currentThread]);
    
            //  在新开的子线程中,任务1、2、3在主线程中执行
            dispatch_queue_t queue1 = dispatch_get_main_queue();
            dispatch_sync(queue1, ^{
                NSLog(@"任务1---%@",[NSThread currentThread]);
            });
            dispatch_sync(queue1, ^{
                NSLog(@"任务2---%@",[NSThread currentThread]);
            });
            dispatch_sync(queue1, ^{
                NSLog(@"任务3---%@",[NSThread currentThread]);
            });
        });
    }
    

    打印

    2016-08-01 17:59:57.794 demo[81900:3693593] 新开的子线程---<NSThread: 0x79745ab0>{number = 2, name = (null)}
    2016-08-01 17:59:57.798 demo[81900:3693419] 任务1---<NSThread: 0x79843a10>{number = 1, name = main}
    2016-08-01 17:59:57.799 demo[81900:3693419] 任务2---<NSThread: 0x79843a10>{number = 1, name = main}
    2016-08-01 17:59:57.800 demo[81900:3693419] 任务3---<NSThread: 0x79843a10>{number = 1, name = main}
    
    2.4 GCD其它函数
    1. 栅栏函数 dispatch_barrier_async(queue, ^{ });
      在任务前面的异步任务都执行完后才会执行它,并且等它执行完后,后面的异步任务才能开始执行
      注意:
      1.>此函数加入全局队列示无效的,即queue不能是全剧队列
      2.>如果任务是同步的则会在当前的线程中执行,异步的话在新线程中执行

    🍐

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        dispatch_queue_t queue = dispatch_queue_create("com.demo.bingfa", DISPATCH_QUEUE_CONCURRENT);
        
        dispatch_async(queue, ^{
            NSLog(@"任务1---%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务2---%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务3---%@",[NSThread currentThread]);
        });
        
        dispatch_barrier_async(queue, ^{
            NSLog(@"任务4---%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务5---%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务6---%@",[NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务7---%@",[NSThread currentThread]);
        });
    }
    

    打印(任务4总是在任务1、2、3和5、6、7的中间)

    2016-08-01 20:55:44.075 demo[85715:3735784] 任务2---<NSThread: 0x7a8746e0>{number = 3, name = (null)}
    2016-08-01 20:55:44.075 demo[85715:3735778] 任务1---<NSThread: 0x7a96ff10>{number = 2, name = (null)}
    2016-08-01 20:55:44.075 demo[85715:3735777] 任务3---<NSThread: 0x7a67a470>{number = 4, name = (null)}
    2016-08-01 20:55:44.077 demo[85715:3735777] 任务4---<NSThread: 0x7a67a470>{number = 4, name = (null)}
    2016-08-01 20:55:44.078 demo[85715:3735777] 任务5---<NSThread: 0x7a67a470>{number = 4, name = (null)}
    2016-08-01 20:55:44.078 demo[85715:3735778] 任务6---<NSThread: 0x7a96ff10>{number = 2, name = (null)}
    2016-08-01 20:55:44.078 demo[85715:3735784] 任务7---<NSThread: 0x7a8746e0>{number = 3, name = (null)}
    

    信号量的使用 --- 但以上任务2中存在其它异步并发任务,如网络请求的时:

       dispatch_queue_t queue = dispatch_queue_create("com.demo.bingfa", DISPATCH_QUEUE_CONCURRENT);
        
        dispatch_async(queue, ^{
           
            // 创建一个信号量为0的信号(红灯)
            dispatch_semaphore_t sema = dispatch_semaphore_create(0);
    
            dispatch_queue_t queue2 = dispatch_queue_create("com.demo.bing", DISPATCH_QUEUE_CONCURRENT);
    
            dispatch_async(queue2, ^{
                [NSThread sleepForTimeInterval:2];
                // 使信号的信号量+1,这里的信号量本来为0,+1信号量为1(绿灯)
                dispatch_semaphore_signal(sema);
                NSLog(@"任务2---%@",[NSThread currentThread]);
            });
            NSLog(@"任务2---%@",[NSThread currentThread]);
            // 开启信号等待,设置等待时间为永久,直到信号的信号量大于等于1(绿灯)
            dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        });
        dispatch_async(queue, ^{
            NSLog(@"任务3---%@",[NSThread currentThread]);
        });
        
        dispatch_barrier_async(queue, ^{
            NSLog(@"任务4---%@",[NSThread currentThread]);
        });
    

    2.队列组
    能实现在一个或则多个任务执行完之后,在执行特定的任务。例如:A任务和B任务并发执行,C任务需要在A任务和B任务都执行完之后再执行,这时候就可以通过队列组来实现
    🍐

    - (void)viewDidLoad {
        [super viewDidLoad];
        dispatch_group_t group = dispatch_group_create();
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"任务1---%@",[NSThread currentThread]);
        });
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"任务2---%@",[NSThread currentThread]);
        });
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"任务3---%@",[NSThread currentThread]);
        });
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"任务4---%@",[NSThread currentThread]);
        });
        dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"任务5---%@",[NSThread currentThread]);
        });
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"任务6---%@",[NSThread currentThread]);
        });
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"任务7---%@",[NSThread currentThread]);
        });
    }
    

    打印: 你会发现任务5永远都是队列组中最后执行的一个

    2016-08-01 22:10:55.218 demo[90162:3774195] 任务1---<NSThread: 0x7af959d0>{number = 2, name = (null)}
    2016-08-01 22:10:55.218 demo[90162:3774194] 任务2---<NSThread: 0x7b1346f0>{number = 3, name = (null)}
    2016-08-01 22:10:55.218 demo[90162:3774216] 任务6---<NSThread: 0x7b06cf00>{number = 6, name = (null)}
    2016-08-01 22:10:55.218 demo[90162:3774215] 任务4---<NSThread: 0x7af95fe0>{number = 5, name = (null)}
    2016-08-01 22:10:55.218 demo[90162:3774199] 任务3---<NSThread: 0x7ae30250>{number = 4, name = (null)}
    2016-08-01 22:10:55.219 demo[90162:3774217] 任务7---<NSThread: 0x7b135bb0>{number = 7, name = (null)}
    2016-08-01 22:10:55.220 demo[90162:3774217] 任务5---<NSThread: 0x7b135bb0>{number = 7, name = (null)}
    
    3.NSOperation
    3.1 概念

    NSOperation是对GCD的封装;本身是一个抽象类,只能使用它的三个子类;和NSOperationQueue结合使用实现多线程并发

    3.2 NSOperation和NSOperationQueue的理解
    NSOperation三个子类

    -NSInvocationOperation

    - (void)viewDidLoad {
       [super viewDidLoad];
       //  不加入队列执行开始操作
       NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(addOperation:) object:@"NEW"];
       [operation start];
    }
    - (void)addOperation:(NSString *)name {
       //  在主线程中执行,没有意义
       NSLog(@"%@",[NSThread currentThread]);
    }
    

    -NSBlockOperation
    创建操作时携带的任务在主线程,操作后面额外添加的任务,系统自动开启线程执行

    - (void)viewDidLoad {
        [super viewDidLoad];
        //  不加入队列执行开始操作
        NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
            //  在主线程中执行
            NSLog(@"任务1---%@",[NSThread currentThread]);
        }];
        [operation addExecutionBlock:^{
            //  系统根据需要自动开启线程
            NSLog(@"任务2---%@",[NSThread currentThread]);
        }];
        [operation addExecutionBlock:^{
            //  系统根据需要自动开启线程
            NSLog(@"任务3---%@",[NSThread currentThread]);
        }];
        [operation addExecutionBlock:^{
            //  系统根据需要自动开启线程
            NSLog(@"任务4---%@",[NSThread currentThread]);
        }];
        [operation start];
    }
    

    -自定义NSOperation
    一般操作过于复杂时可以使用自定义NSOperation,具有隐蔽性和可重复利用的好处

    #import "JYOperation.h"
    @implementation JYOperation
    - (void)main {
        NSLog(@"%@",[NSThread currentThread]);
    }
    @end
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        //  不添加到队列的话,任务在主线程执行,没有意义
        JYOperation *operation = [[JYOperation alloc] init];
        [operation start];
    }
    
    NSOperationQueue

    - 主队列
    添加到主队列中的任务都在主线程中执行
    -非主队列
    任务在子线程中执行,控制任务以串行或并发的方式执行,具体通过设置队列的maxConcurrentOperationCount(最大并发数)属性来控制

    注意:

    1.maxConcurrentOperationCount必须在操作添加到队列之前设置才有效
    2.maxConcurrentOperationCount 默认为-1,即默认任务是并发执行;等于0时,不执行任务,无意义;等于1时,串行执行任务;等于n时,并发数为n,允许n个任务是同时执行的

    - (void)viewDidLoad {
        
        //  2.非主队列
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        queue.maxConcurrentOperationCount = 3;
        [queue addOperationWithBlock:^{
            NSLog(@"任务1---%@",[NSThread currentThread]);
        }];
        [queue addOperationWithBlock:^{
            NSLog(@"任务2---%@",[NSThread currentThread]);
        }];
        [queue addOperationWithBlock:^{
            NSLog(@"任务3---%@",[NSThread currentThread]);
        }];
        [queue addOperationWithBlock:^{
            NSLog(@"任务4---%@",[NSThread currentThread]);
        }];
        [queue addOperationWithBlock:^{
            NSLog(@"任务5---%@",[NSThread currentThread]);
        }];
        [queue addOperationWithBlock:^{
            NSLog(@"任务6---%@",[NSThread currentThread]);
        }];
    }
    

    打印

    2016-08-02 10:10:56.874 demo[99820:3887770] 任务1---<NSThread: 0x7a98b340>{number = 2, name = (null)}
    2016-08-02 10:10:56.874 demo[99820:3887814] 任务3---<NSThread: 0x7a71c690>{number = 4, name = (null)}
    2016-08-02 10:10:56.874 demo[99820:3887769] 任务2---<NSThread: 0x7a71c450>{number = 3, name = (null)}
    2016-08-02 10:10:56.875 demo[99820:3887814] 任务5---<NSThread: 0x7a71c690>{number = 4, name = (null)}
    2016-08-02 10:10:56.876 demo[99820:3887810] 任务6---<NSThread: 0x7a71c840>{number = 5, name = (null)}
    2016-08-02 10:10:56.876 demo[99820:3887770] 任务4---<NSThread: 0x7a98b340>{number = 2, name = (null)}
    
    3.3 操作和队列结合(两种方式)
    - (void)viewDidLoad {
        //  方式1:将操作加入队列
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"任务1---%@",[NSThread currentThread]);
        }];
        [queue addOperation:operation];
        
        //  方式2:通过队列直接加操作
        [queue addOperationWithBlock:^{
            NSLog(@"任务2---%@",[NSThread currentThread]);
        }];
    }
    

    补充(暂停、恢复和取消)

    - (void)viewDidLoad {
        
        self.queue = [[NSOperationQueue alloc] init];
        //  任务暂停后可以恢复执行
        if (self.queue.isSuspended) {
            self.queue.suspended = NO;
        }
        //  任务取消后不可在恢复执行
        [self.queue cancelAllOperations];
    }
    
    3.4 设置操作依赖

    通过调用操作[operation addDependency:]方法,可实现不同操作按指定的顺序执行

    - (void)viewDidLoad {
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        
        NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"操作1---");
        }];
        NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"操作2---");
        }];
        //  operation1依赖operation2,operation2执行完才能执行operation1
        [operation1 addDependency:operation2];
        [queue addOperation:operation1];
        [queue addOperation:operation2];
    }
    

    打印

    2016-08-02 11:02:19.161 demo[3839:3930104] 操作2---
    2016-08-02 11:02:19.162 demo[3839:3930104] 操作1---
    

    🍐有一种需求:前两个异步任务都执行完之后才开始执行第三个
    任务

    - (void)viewDidLoad {
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        
        NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"操作1---");
        }];
        NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"操作2---");
        }];
        NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"操作3---");
        }];
    
        [operation3 addDependency:operation1];
        [operation3 addDependency:operation2];
        [queue addOperation:operation1];
        [queue addOperation:operation2];
        [queue addOperation:operation3];
    }
    

    打印

    2016-08-02 11:05:21.480 demo[4099:3932866] 操作2---
    2016-08-02 11:05:21.480 demo[4099:3932865] 操作1---
    2016-08-02 11:05:21.482 demo[4099:3932865] 操作3---
    
    4 总结

    以上主要涉及到开发中常用的一些内容,另外至于GCD和NSOperation线程间的通信,其实常用到的是异步操作后回到主线程,只要将需要回到主线程的任务添加到主队列即可

    相关文章

      网友评论

          本文标题:iOS-多线程(NSThread+GCD+NSOperation

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