3.多线程NSOperation

1.NSOperation的基本操作

使用NSOperation的两个子类,NSInvocationOperation 和 NSBlockOperation 创建操作,然后将操作添加到队列中去执行

// NSOperation

    // 1. 实例化 NSOperation 子类对象:NSInvocationOperation
    NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test1) object:nil];

    // 2. 实例化 NSOperation 子类对象
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        //
        NSLog(@"耗时操作2------------");
    }];

    // NSOperationQueue

    // 1.获取主队列
    NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];

    // 2.创建非主队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    // NSOperation使用: 将操作添加到队列中!
    [mainQueue addOperation:op];

    [queue addOperation:op1];

2.NSOperation定义的操作可以直接用start启动,相当于直接执行,入口是NSOperation中定义的main方法

    // 1. 实例化操作对象
    NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test1) object:nil];

    NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test2) object:nil];

    NSInvocationOperation *op3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test3) object:nil];

    // 需求: 1. 三个操作都是耗时操作!

//    // 2. 创建非主队列
//    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//
//    // 3. 将操作添加到非主队列中
//    [queue addOperation:op1];
//    [queue addOperation:op2];
//    [queue addOperation:op3];

//    // 需求: 2. 三个操作都是UI操作
//    NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
//    // 相当于 GCD 中的 异步函数 + 主队列!
//    [mainQueue addOperation:op1];
//    [mainQueue addOperation:op2];
//    [mainQueue addOperation:op3];

    // NSOperation 执行方式2: 直接启动!直接在当前线程执行!
    [op1 start];
    [op2 start];
    [op3 start];

    // NSOperation 对象的入口是定义在自身内部的 main 方法;
    // 当将操作添加到操作队列中或者直接调用操作的 start 方法之后,内部都会调用 main 方法,所有两者都能够执行操作!

    NSLog(@"touchesEnd");

}

- (void)test1
{
    NSLog(@"test1----------%@",[NSThread currentThread]);
}

- (void)test2
{
    NSLog(@"test2----------%@",[NSThread currentThread]);
}

- (void)test3
{
    NSLog(@"test3----------%@",[NSThread currentThread]);
}

3.使用block

NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"222222222----%@",[NSThread currentThread]);
    }];

    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"33333333----%@",[NSThread currentThread]);
    }];

    // 1.将操作添加到主队列中
    //    [[NSOperationQueue mainQueue] addOperation:op1];
    //    [[NSOperationQueue mainQueue] addOperation:op2];
    //    [[NSOperationQueue mainQueue] addOperation:op3];

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation:op1];
    [queue addOperation:op2];
    [queue addOperation:op3];

4.向blockOperation中追加任务

// 当 NSBlockOperation中的任务数 > 1 之后, 无论是将操作添加到主线程,还是在主线程直接执行 start ,NSBlockOperation中的任务执行顺序都不确定,执行线程也不确定!

// 一半在开发的时候,要避免向 NSBlockOperation 中追加任务!

// 如果任务都是在子线程中执行,并且不需要保证执行顺序,可以直接追加任务!

// 1. 实例化操作对象
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"11111111----%@",[NSThread currentThread]);
    }];

    // 往当前操作中追加操作
    [op1 addExecutionBlock:^{

        NSLog(@"追加任务1%@",[NSThread currentThread]);

    }];

    // 往当前操作中追加操作
    [op1 addExecutionBlock:^{

        NSLog(@"追加任务2%@",[NSThread currentThread]);

    }];

    // 当 NSBlockOperation中的任务数 > 1 之后, 无论是将操作添加到主线程,还是在主线程直接执行 start ,NSBlockOperation中的任务执行顺序都不确定,执行线程也不确定!
    // 一半在开发的时候,要避免向 NSBlockOperation 中追加任务!
    // 如果任务都是在子线程中执行,并且不需要保证执行顺序,可以直接追加任务!

5.直接通过操作队列添加任务

// 直接通过操作队列添加任务!

    //将block中的内容当做一个操作添加到主队列中!
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{

        NSLog(@"---------1%@",[NSThread currentThread]);

    }];

    [[NSOperationQueue mainQueue] addOperationWithBlock:^{

        NSLog(@"---------2%@",[NSThread currentThread]);

    }];

    [[NSOperationQueue mainQueue] addOperationWithBlock:^{

        NSLog(@"---------3%@",[NSThread currentThread]);

    }];

    [[[NSOperationQueue alloc] init] addOperationWithBlock:^{

        NSLog(@"---------4%@",[NSThread currentThread]);

    }];

    [[[NSOperationQueue alloc] init] addOperationWithBlock:^{

        NSLog(@"---------5%@",[NSThread currentThread]);

    }];

    [[[NSOperationQueue alloc] init] addOperationWithBlock:^{

        NSLog(@"---------6%@",[NSThread currentThread]);

    }];

6.给操作添加操作依赖,保证操作的顺序执行,避免循环依赖

// NSOperation 相对于 GCD 来说,增加了以下管理线程的功能:
    // 1. NSOperation可以添加操作依赖: 保证操作的执行顺序!  --> 和GCD中将任务添加到一个串行队列中是一样的! 一个串行队列会对应一条线程!

    // GCD 中的按顺序执行(串行队列)----> 串行执行!
    // 添加操作依赖之后,系统有可能串行执行保证任务的执行顺序,还有可能采用线程同步技术,保证任务执行顺序!

    NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test) object:nil];

    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"-------222 %@",[NSThread currentThread]);

    }];

    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"-------333 %@",[NSThread currentThread]);

    }];

    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"-------444 %@",[NSThread currentThread]);

    }];

    // 四个操作都是耗时操作! 并且要求按顺序执行! 操作2是UI操作!

    // 添加操作依赖的注意点:
    // 1. 不要添加循环依赖!
    // 2. 一定要在将操作添加到操作队列中之前添加操作依赖!

    // 优点: 对于不同操作队列中的操作,操作依赖依然有效!

    // 添加操作依赖!
    [op2 addDependency:op1];

    [op3 addDependency:op2];

    [op4 addDependency:op3];

   // [op2 addDependency:op3];
   // [op1 addDependency:op4];

    // 将操作添加到操作队列中
    NSOperationQueue *quque = [[NSOperationQueue alloc] init];

    [quque addOperation:op3];
    [quque addOperation:op1];
    [quque addOperation:op4];

    // 将操作2 添加到主队列中
    [[NSOperationQueue mainQueue] addOperation:op2];

7.NSOperation的高级操作,暂停/恢复/取消/设置最大线程数

  // 遇到并发编程,什么时候选择 GCD ,什么时候选择 NSOperation!

// 1.简单的开启线程/回到主线程,选择 GCD : 效率更高,简单!

// 2.需要管理操作(考虑到与用户交互!),使用 NSOperation!

 // NSOperation高级操作:

    // 1. 添加操作依赖!
    // 2. 管理操作: 重点! 是操作队列的方法!
    // 2.1 暂停/恢复 取消 操作!
    // 2.2 开启合适的线程数量!(最多不超过6条!)

    // 一半开发的时候,会将操作队列设置成一个全局的变量(属性)!
    //

    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"0----------");

        [self test];
    }];

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    [queue addOperationWithBlock:^{

        [self test];
    }];

    [queue addOperation:op];

    // 1. 暂停操作// 开始滚动的时候
    [queue setSuspended:YES];

    // 2. 恢复操作// 滚动结束的时候
    [queue setSuspended:NO];

    // 3. 取消所有操作// 接收到内存警告
    [queue cancelAllOperations];

    // 3补充: 取消单个操作!是操作的方法!
    [op cancel];

    // 设置最大并发数,开启合适的线程数量 // 实例化操作队列的时候
    [queue setMaxConcurrentOperationCount:6];

    // 遇到并发编程,什么时候选择 GCD ,什么时候选择 NSOperation!
    // 1.简单的开启线程/回到主线程,选择 GCD : 效率更高,简单!
    // 2.需要管理操作(考虑到与用户交互!),使用 NSOperation!

8.block的循环引用问题,使用__weak typeof(self)weakself = self;弱引用

#import "HMViewController.h"

@interface HMViewController ()

// 全局操作队列
@property(nonatomic ,strong)NSOperationQueue *queue;

//
@property(nonatomic ,strong)NSMutableArray *array;

@end

@implementation HMViewController

-(NSOperationQueue *)queue
{
    if (!_queue) {

        _queue = [[NSOperationQueue alloc] init];

        [_queue setMaxConcurrentOperationCount:6];
    }

    return _queue;
}

-(NSMutableArray *)array
{
    if (!_array) {
        _array = [NSMutableArray array];
    }
    return _array;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor orangeColor];
    //
    NSLog(@"控制器创建成功!");

}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touchesBegan");
    // block!

    // 1. 创建操作

    // 为了防止 block 中使用 self 出现的循环引用问题! 一般在 block中使用 self 的时候,要使用 self 的弱引用!!!

    // 为了安全,block中出现self,都使用 弱引用写法!

    // weakself : 下面就是 self 的弱引用写法!
    __weak typeof(self)weakself = self;

    // __weak HMViewController *wself = self;
    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{

        [self test];
    }];

    // 将操作添加到 array 中!
    [self.array addObject:op];

    // self --> queue -->op --> block --> self  : 循环引用链条!

    // 2. 将操作添加到操作队列中
    // 因为操作执行完毕之后,操作队列会自动释放其中的操作,所以,在操作中(NSblockOperation)block里有了 self,没有关系,能够释放.不会造成循环引用!
    [self.queue addOperation:op];

}

-(void)test
{
    NSLog(@"------%@",[NSThread currentThread]);
}

-(void)dealloc
{
    NSLog(@"控制器销毁了!");
}

9.线程间通信,在子线程下载图片,在主线程更新UI

// 1 在子线程下载图片

    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{

        // 如果图片地址中出现了 & 符号,换一张图片!
        // image :下载好的网络图片
        UIImage *image = [self downloadWebImageWithUrlString:@"http://pic14.nipic.com/20110522/7411759_164157418126_2.jpg"];

        // 回到主线程!
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{

            // 显示图片
            self.imageView.image = image;
        }];
    }];

    [self.queue addOperation:op];

    NSLog(@"touchesEnd");

}

// 下载网络图片的方法
- (UIImage *)downloadWebImageWithUrlString:(NSString *)urlString
{
    NSURL *url = [NSURL URLWithString:urlString];

    // 下载方法!耗时方法!
    NSData *data = [NSData dataWithContentsOfURL:url];

    UIImage *image = [UIImage imageWithData:data];

    return image;
}

10.自定义NSOperation,继承NSOperation,重写mian方法

加自动释放池

//
//  HMDownloadOperation.h
//  09-线程间通信
//
//  Created by HM on 16/1/25.
//  Copyright © 2016年 HM. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@class HMDownloadOperation;

@protocol HMDownloadOperationDelegate <NSObject>

-(void)downloadImageWithOperation:(HMDownloadOperation *)operation;

@end

@interface HMDownloadOperation : NSOperation

// 代理属性
@property(nonatomic ,weak) id<HMDownloadOperationDelegate> delegate;

// 写一个图片属性// 下载好的图片
@property(nonatomic ,strong) UIImage *image;

// 图片下载地址
@property(nonatomic ,copy)NSString *urlString;

@end
//
//  HMDownloadOperation.m
//  09-线程间通信
//
//  Created by HM on 16/1/25.
//  Copyright © 2016年 HM. All rights reserved.
//

#import "HMDownloadOperation.h"

@implementation HMDownloadOperation

// 重写 NSOperation 的 main 方法!
// 当把自定义的操作添加到操作队列中,或者直接调用 操作的  start 方法之后,都会自动来执行 main 方法中的内容!
-(void)main
{
    // 为了能够及时释放内存,一般会手动书写一个 autoreleasepool!苹果官方文档不要求写!
    @autoreleasepool {

        NSLog(@"----------%@",[NSThread currentThread]);

        self.image = [self downloadWebImageWithUrlString:self.urlString];

        NSLog(@"image:%@",self.image);

        // 通知/代理/block :为了保证在不同对象之间传值的准确性!采用的是同步传值的方法!

        // 回到主线程,执行代理方法:
        dispatch_async(dispatch_get_main_queue(), ^{
            // 执行代理方法
            if ([self.delegate respondsToSelector:@selector(downloadImageWithOperation:)]) {
                [self.delegate downloadImageWithOperation:self];
            }
        });
    }
}

// 下载网络图片的方法
- (UIImage *)downloadWebImageWithUrlString:(NSString *)urlString
{
    NSURL *url = [NSURL URLWithString:urlString];

    // 下载方法!耗时方法!
    NSData *data = [NSData dataWithContentsOfURL:url];

    UIImage *image = [UIImage imageWithData:data];

    return image;
}

@end

11.操作完成之后的回调completionBlock

NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"--------%@",[NSThread currentThread]);

    }];

    // 操作完成之后的回调!
//    op.completionBlock = ^(){
//
//        NSLog(@"操作执行完毕!");
//
//    };
    [op setCompletionBlock:^{

        NSLog(@"操作执行完毕!");
    }];

    [op start];
时间: 2024-10-13 12:47:13

3.多线程NSOperation的相关文章

【iOS】多线程NSOperation

NSOperation是苹果封装的一套多线程的东西,不像GCD是纯C语言的,这个是OC的.但相比较之下GCD会更快一些,但本质上NSOPeration是多GDC的封装. 一.NSOperation与GCD的比较 GCD是基于c的底层api,NSOperation属于object-c类.ios首先引入的是NSOperation,IOS4之后引入了GCD和NSOperationQueue并且其内部是用gcd实现的. GCD优点:GCD主要与block结合使用.代码简洁高效.执行效率稍微高点. NSO

多线程----NSOperation

NSOperation是Cocoa中的一个抽象类,用来封装单个任务和代码执行一项操作,由于是抽象类,所以不能直接实例化使用,必须定义子类继承该抽象类来实现, 使用NSOperation的方式有两种: 一种是用定义好的两个子类: NSInvocationOperation 和 NSBlockOperation,有相关的使用方法. NSOperation的子类NSInvocationOperation提供了一套简单的多线程编程方法,是IOS多线程编程中最简单的一种实现方式. 另一种是继承NSOper

iOS:操作队列实现多线程NSOperation

NSOperation具体使用:直接继承NSObject 它的子类有:NSBlockOperation.NSInvocationOperation 还有一个必须的类,队列,用来装创建的线程 NSOperationQueue 理解:这个方式是如何实现多线程呢?是通过操作队列来实现多线程的.即主线程是一个主队列,再创建一个队列并将其他的线程加入其中同步执行.如果对共享资源的争夺放在主线程队列中,则不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上:否则的话,仍需要关心数据同步的问

多线程NSOperation使用方法

/*------------------------------  NSOperation使用   -----------------------------------*/ 重点:操作 NSOperation 和操作队列 NSOperationQueue! { 1.NSOperation(操作)简介: NSOperation: // 本质是对 GCD 的封装, OC 语言. NSOperation 和 GCD 的比较: GCD使用场合: 一些简单的需求,简单的多线程操作. //简单高效 NSO

四:多线程--NSOperation简单介绍

一.NSOperation简介 1.NSOperation的作?:配合使用NSOperation和NSOperationQueue也能实现多线程编程 NSOperation和NSOperationQueue实现多线程的具体步骤: (1)先将需要执行的操作封装到一个NSOperation对象中 (2)然后将NSOperation对象添加到NSOperationQueue中 (3)系统会?动将NSOperationQueue中的NSOperation取出来 (4)将取出的NSOperation封装的

iOS开发——多线程OC篇&amp;(九)多线程NSOperation介绍

NSOperation介绍 一.NSOperation简介 1.简单说明 NSOperation的作?:配合使用NSOperation和NSOperationQueue也能实现多线程编程 NSOperation和NSOperationQueue实现多线程的具体步骤: (1)先将需要执行的操作封装到一个NSOperation对象中 (2)然后将NSOperation对象添加到NSOperationQueue中 (3)系统会?动将NSOperationQueue中的NSOperation取出来 (4

iOS中的多线程 NSOperation

在ios中,使用多线程有三种方式,分别是:NSThread.NSOperation和NSOperationQueue.GCD,在本节,主要讲解一下NSOperation的使用. NSOperation和NSOperationQueue这种方式实际上是将NSOperation的对象放到一个NSOperationQueue队列中,然后依次启动操作,类似于线程池的使用. 在使用的过程中,NSOperation的操作使用的是它的子类,分别是NSInvocationOperation和NSBlockOpe

多线程nsoperation

不能直接使用NSOperation,而是使用系统定义的子类来完成实际任务 两个子类:NSInvocationOperation和 NSBlockOperation 他们只能执行一次任务,而且不能再次执行他,可以将它添加到一个操作队列中执行,这个可以用NSOperationQueue实现 NSOperation的创建方式,可以用定义好的两个子类创建 //第一种 NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTa

IOS多线程--NSOperation\NSOperationQueue

iOS中,有多种多线程方式,但是,苹果公司建议我们用NSOperation技术 1.GCD是纯C的,对面向对象的程序员不友好 2.GCD对编程管理还不是很强大 NSOperation 其实底层实现是基于GCD来做的 dispatch_queue_t ==  NSOperationQueue dispatch_async == NSOperation dispatch_sync  == NSOperation NSOperation是个抽象类 使用它的两个子类 NSInvocationOperat

iOS之多线程NSOperation

目前在 iOS 和 OS X 中有两套先进的同步 API 可供我们使用:NSOperation 和 GCD .其中 GCD 是基于 C 的底层的 API ,而 NSOperation 则是 GCD 实现的 Objective-C API. 1. 什么时候使用NSOperationQueue而不是GCD 比如你可能写过类似这样的代码(这样来请求网络数据): 1 dispatch_async(_Queue, ^{ 2 3 //请求数据 4 NSData *data = [NSData dataWit