美文网首页
NSOperation简介

NSOperation简介

作者: 小小鸟他大爷 | 来源:发表于2021-02-03 16:18 被阅读0次

    1.默认情况下,NSOperation并不具备封装操作的能力,必须使用它的子类,使用NSOperation子类的方式有3种:

    1> NSInvocationOperation

    2> NSBlockOperation

    3> 自定义子类继承NSOperation,实现内部相应的方法

    这讲先介绍如何用NSOperation封装一个操作,后面再结合NSOperationQueue来使用。

    ## 一、NSInvocationOperation

    NSInvocationOperation *operation = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run:) object:@"mj"] autorelease]; 2 [operation start];

    * 第1行初始化了一个NSInvocationOperation对象,它是基于一个对象和selector来创建操作

    * 第2行调用了start方法,紧接着会马上执行封装好的操作,也就是会调用self的run:方法,并且将@"mj"作为方法参数

    * 这里要注意:默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作。只有将operation放到一个NSOperationQueue中,才会异步执行操作。

    ## 二、NSBlockOperation

    ### 1.同步执行一个操作

    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){ 2        NSLog(@"执行了一个新的操作");

    3 }];

    4  // 开始执行任务

    5 [operation start];

    * 第1行初始化了一个NSBlockOperation对象,它是用一个Block来封装需要执行的操作

    * 第2行调用了start方法,紧接着会马上执行Block中的内容

    * 这里还是在当前线程同步执行操作,并没有异步执行

    ### 2.并发执行多个操作

    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){

    2   NSLog(@"执行第1次操作,线程:%@", [NSThread currentThread]);

    3 }];

    4

    5 [operation addExecutionBlock:^() {

    6   NSLog(@"又执行了1个新的操作,线程:%@", [NSThread currentThread]);

    7 }];

    8

    9 [operation addExecutionBlock:^() {

    10   NSLog(@"又执行了1个新的操作,线程:%@", [NSThread currentThread]);

    11 }];

    12

    13 [operation addExecutionBlock:^() {

    14   NSLog(@"又执行了1个新的操作,线程:%@", [NSThread currentThread]);

    15 }];

    16

    17 // 开始执行任务

    18 [operation start];

    * 第1行初始化了一个NSBlockOperation对象

    * 分别在第5、9、13行通过addExecutionBlock:方法添加了新的操作,包括第1行的操作,一共封装了4个操作

    * 在第18行调用start方法后,就会并发地执行这4个操作,也就是会在不同线程中执行

    <pre style="margin: 0px; padding: 0px; overflow: auto; white-space: pre; word-wrap: break-word; font-family: &quot;Courier New&quot; !important; font-size: 18px !important;">1 2013-02-02 21:38:46.102 thread[4602:c07]

    又执行了1个新的操作,线程:<NSThread: 0x7121d50>{name = (null), num = 1} 2 2013-02-02 21:38:46.102 thread[4602:3f03]

    又执行了1个新的操作,线程:<NSThread: 0x742e1d0>{name = (null), num = 5} 3 2013-02-02 21:38:46.102 thread[4602:1b03]

    执行第1次操作,线程:<NSThread: 0x742de50>{name = (null), num = 3}

    4 2013-02-02 21:38:46.102 thread[4602:1303] 又执行了1个新的操作,线程:<NSThread: 0x7157bf0>{name = (null), num = 4}</pre>

    可以看出,每个操作所在线程的num值都不一样,说明是不同线程

    ## 三、NSOperation的其他用法

    ### 1.取消操作

    operation开始执行之后, 默认会一直执行操作直到完成,我们也可以调用cancel方法中途取消操作

    ### 2.在操作完成后做一些事情

    如果想在一个NSOperation执行完毕后做一些事情,就调用NSOperation的setCompletionBlock方法来设置想做的事情

    operation.completionBlock = ^() {

        NSLog(@"执行完毕");

    }

    当operation封装的操作执行完毕后,就会回调Block里面的内容

    ## 四、自定义NSOperation

    如果NSInvocationOperation和NSBlockOperation不能满足需求,我们可以直接新建子类继承NSOperation,并添加任何需要执行的操作。如果只是简单地自定义NSOperation,只需要重载-(void)main这个方法,在这个方法里面添加需要执行的操作。

    下面写个子类DownloadOperation来下载图片

    ### 1.继承NSOperation,重写main方法

    #### DownloadOperation.h

    #import <Foundation/Foundation.h>

    @protocol DownloadOperationDelegate;

    @interface DownloadOperation : NSOperation // 图片的url路径

    @property (nonatomic, copy) NSString *imageUrl; // 代理

    @property (nonatomic, assign) id<DownloadOperationDelegate> delegate;

    - (id)initWithUrl:(NSString *)url delegate:(id<DownloadOperationDelegate>)delegate;

    @end

    // 图片下载的协议

    @protocol DownloadOperationDelegate <NSObject>

    - (void)downloadFinishWithImage:(UIImage *)image; @end

    #### DownloadOperation.m

    #import "DownloadOperation.h"

    2

    3 @implementation DownloadOperation

    4 @synthesize delegate = _delegate; //使用@synthesize 只有一个目的——给实例变量起个别名,或者说为同一个变量添加两个名字。

    5 @synthesize imageUrl = _imageUrl;

    6

    7 // 初始化

    8 - (id)initWithUrl:(NSString *)url delegate:(id<DownloadOperationDelegate>)delegate {

    9    if (self = [super init]) {

    10        self.imageUrl = url;

    11        self.delegate = delegate;

    12 }

    13    return self;

    14 }

    15 // 释放内存

    16 - (void)dealloc {

    17 [super dealloc];

    18 [_imageUrl release];

    19 }

    20

    21 // 执行主任务

    22 - (void)main {

    23    // 新建一个自动释放池,如果是异步执行操作,那么将无法访问到主线程的自动释放池

    24 @autoreleasepool {

    25        // ....

    26 }

    27 }

    28 @end

    * 在第22行重载了main方法,等会就把下载图片的代码写到这个方法中

    * 如果这个DownloadOperation是在异步线程中执行操作,也就是说main方法在异步线程调用,那么将无法访问主线程的自动释放池,所以在第24行创建了一个属于当前线程的自动释放池

    ### 2.正确响应取消事件

    * 默认情况下,一个NSOperation开始执行之后,会一直执行任务到结束,就比如上面的DownloadOperation,默认会执行完main方法中的所有代码。

    * NSOperation提供了一个cancel方法,可以取消当前的操作。

    * 如果是自定义NSOperation的话,需要手动处理这个取消事件。比如,一旦调用了cancel方法,应该马上终止main方法的执行,并及时回收一些资源。

    * 处理取消事件的具体做法是:在main方法中定期地调用isCancelled方法检测操作是否已经被取消,也就是说是否调用了cancel方法,如果返回YES,表示已取消,则立即让main方法返回。

    * 以下地方可能需要调用isCancelled方法:

    *  在执行任何实际的工作之前,也就是在main方法的开头。因为取消可能发生在任何时候,甚至在operation执行之前。

    *  执行了一段耗时的操作之后也需要检测操作是否已经被取消

    1 - (void)main {

    2    // 新建一个自动释放池,如果是异步执行操作,那么将无法访问到主线程的自动释放池

    3    @autoreleasepool {

    4        if (self.isCancelled) return;

    5       

    6        // 获取图片数据

    7        NSURL *url = [NSURL URLWithString:self.imageUrl];

    8        NSData *imageData = [NSData dataWithContentsOfURL:url];

    9       

    10        if (self.isCancelled) {

    11            url = nil;

    12            imageData = nil;

    13            return;

    14 }

    15       

    16        // 初始化图片

    17        UIImage *image = [UIImage imageWithData:imageData];

    18       

    19        if (self.isCancelled) {

    20            image = nil;

    21            return;

    22 }

    23       

    24        if ([self.delegate respondsToSelector:@selector(downloadFinishWithImage:)]) {

    25            // 把图片数据传回到主线程

    26            [(NSObject *)self.delegate performSelectorOnMainThread:@selector(downloadFinishWithImage:) withObject:image waitUntilDone:NO];

    27 }

    28 }

    29 }</pre>

    * 在第4行main方法的开头就先判断operation有没有被取消。如果被取消了,那就没有必要往下执行了

    * 经过第8行下载图片后,在第10行也需要判断操作有没有被取消

    * 总之,执行了一段比较耗时的操作之后,都需要判断操作有没有被取消

    * 图片下载完毕后,在第26行将图片数据传递给了代理(delegate)对象

    相关文章

      网友评论

          本文标题:NSOperation简介

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