iOS-多线程之NSOperation

来源:互联网 发布:linux中rpm文件 编辑:程序博客网 时间:2024/05/19 17:57

继之前的NSThread、GCD,今天学习下NSOperation。NSOperation是个抽象类,并不直接实现多线程编程的能力,必须使用它的子类,配合使用NSOperationQueue队列实现多线程编程。

  • NSInvocationOperation
    - (通过initWithTarget:执行任务)
  • NSBlockOperation
    - (通过block执行任务)
  • 自定义子类继承自NSOperation,实现内部相应的方法
    - (通过重写父类的方法,执行任务)

NSInvocationOperation 的运用

// 通过 NSInvocationOperation 创建任务-(void)NSInvocationOperation {    // 创建任务    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(do_method) object:nil];    // 开始任务    [operation start];}-(void)do_method {    NSLog(@"---任务01---%@",[NSThread currentThread]);}

总结:默认主线程执行,不开启新线程


NSBlockOperation 的运用

// 通过 NSBlockOperation 创建任务-(void)NSBlockOperation {    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"---任务01---%@",[NSThread currentThread]);    }];    // 只要NSBlockOperation封装的操作数 > 1,就会异步执行操作    // 追加额外的任务    [operation addExecutionBlock:^{        NSLog(@"---任务02---%@",[NSThread currentThread]);    }];    // 追加额外的任务    [operation addExecutionBlock:^{        NSLog(@"---任务03---%@",[NSThread currentThread]);    }];    // 开始队列任务    [operation start];}

这里写图片描述
总结:如果任务只有一条,不开启新线程,主线程执行;当添加额外的任务时,会开启新的线程去执行任务


自定义 NSOperation 的运用

需要在自定义的XMOperation文件中重写 - (void)main; 方法// 将需要执行的任务方法main函数中,当外界调用自己实例的start方法时,执行该任务-(void)main {    NSLog(@"---我是自定义队列任务---%@",[NSThread currentThread]);}// 自定义 NSOperation-(void)DIYOperation {    // 自定义继承自 NSOperation 的任务    XMOperation *operation = [[XMOperation alloc] init];    // 开始任务(去实现自定义类方法中的main函数)    [operation start];}

这里写图片描述
总结:当调用 [operation start] 后执行 - (void)main; 方法


NSOperationQueue 的运用

-(void)operationQueue {    // 创建队列    NSOperationQueue *queue = [[NSOperationQueue alloc] init];    // 通过 NSInvocationOperation 创建任务    NSInvocationOperation *opt = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(do_method) object:nil];    // 通过 NSBlockOperation 创建任务    NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"---任务02---%@",[NSThread currentThread]);    }];    // 添加任务到队列中    [queue addOperation:operation];    [queue addOperation:opt];    // 直接向队列中添加任务    [queue addOperationWithBlock:^{        NSLog(@"---任务03---%@",[NSThread currentThread]);    }];}

这里写图片描述
总结:开启多条线程,并且并发执行任务


最大并发数的使用(maxConcurrentOperationCount)

-(void)maxConcurrentOperationCount {    // 创建队列    NSOperationQueue *queue = [[NSOperationQueue alloc] init];    // 确定最大并发数,当并发数为1时,是串行队列    // 当并发数为n(n>1)时,是并发队列,每次并发执行n条任务    queue.maxConcurrentOperationCount = 2;    // 添加任务到队列中    [queue addOperationWithBlock:^{        NSLog(@"---任务01---%@",[NSThread currentThread]);    }];    [queue addOperationWithBlock:^{        NSLog(@"---任务02---%@",[NSThread currentThread]);    }];    [queue addOperationWithBlock:^{        NSLog(@"---任务03---%@",[NSThread currentThread]);    }];    [queue addOperationWithBlock:^{        NSLog(@"---任务04---%@",[NSThread currentThread]);    }];}
  • 图片 01 (最大并发数为2)
    这里写图片描述
  • 图片 02 (最大并发数为1)
    这里写图片描述
    总结:当最大并发数为1时,开启新线程,但一般只会开启一条,因为此时是串行执行。见图片 01
    当最大并发数大于1时(n(n>1)),开启多条线程,并发执行n条任务。见图片 01

对任务添加依赖的运用(addDependency)

// 添加依赖-(void)addDependency {    // 创建队列    NSOperationQueue *queue = [[NSOperationQueue alloc] init];    // 通过 NSBlockOperation 创建任务    NSBlockOperation *opt1 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"---任务01---%@",[NSThread currentThread]);    }];    NSBlockOperation *opt2 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"---任务02---%@",[NSThread currentThread]);    }];    NSBlockOperation *opt3 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"---任务03---%@",[NSThread currentThread]);    }];    NSBlockOperation *opt4 = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"---任务04---%@",[NSThread currentThread]);    }];    // 添加依赖    [opt3 addDependency:opt4]; // 线程opt3 需要在 opt4 执行完毕后执行    [opt2 addDependency:opt3]; // 线程opt2 需要在 opt3 执行完毕后执行    [opt1 addDependency:opt2]; // 线程opt1 需要在 opt2 执行完毕后执行    // 添加任务到队列中    [queue addOperation:opt1];    [queue addOperation:opt2];    [queue addOperation:opt3];    [queue addOperation:opt4];}

这里写图片描述
总结:开启新线程,但执行顺序受依赖的影响
为每条任务添加依赖,也可以实现串行队列


队列的状态

- 暂停(suspended = YES) - 执行(suspended = NO)- 取消所有任务 (cancelAllOperations)- 判断是否暂停 (isSuspended)
    if (self.queue.isSuspended) { // 队列处于暂停状态        // 恢复队列,继续执行        self.queue.suspended = NO;    } else { // 队列处于正常状态        // 暂停(挂起)队列,暂停执行        self.queue.suspended = YES;    }    // 取消所有队列    [self.queue cancelAllOperations];

线程之间的通信

线程之间的通信模板

// 线程之间的通信-(void)communicateWithOperation {    NSOperationQueue *queue = [[NSOperationQueue alloc] init];    [queue addOperationWithBlock:^{        NSLog(@"---子线程任务---%@",[NSThread currentThread]);        // 回到主线程执行任务        [[NSOperationQueue mainQueue] addOperationWithBlock:^{            NSLog(@"---主线程任务---%@",[NSThread currentThread]);        }];    }];}

这里写图片描述


利用NSOperationQueue在子线程下载图片,主线程显示图片

// 线程之间的通信实例-(void)communicateWithOperationInstance {    // 开辟一个子线程执行图片下载任务    [[[NSOperationQueue alloc] init] addOperationWithBlock:^{        // 图片的网络路径        NSURL *url = [NSURL URLWithString:@"http://xxx.png"];        // 加载图片        NSData *data = [NSData dataWithContentsOfURL:url];        // 生成图片        UIImage *image = [UIImage imageWithData:data];        // 回到主线程,添加图片        [[NSOperationQueue mainQueue] addOperationWithBlock:^{            self.imageView.image = image;        }];    }];}

总结:多线程的学习就到这里了,NSThread、GCD、NSOperation 这三条多线程方法在iOS开发中运用还是比较频繁的,其中GCD的功能最多,可以实现单例,延迟执行,多线程遍历,线程群组,线程阻碍等等。对于任务的分段下载,既可以用GCD的群组,也可以用NSOperation的依赖来实现。最后说一句,学习,一定得去敲,得去写,进步才会快

0 0
原创粉丝点击