Object-c并发三曲---NSOperation的总结

//
//  ViewController.m
//  MultiThread
//
//  Created by liuxiaobing on 2018/7/27.
//  Copyright © 2018 liuxiaobing. All rights reserved.
//

#import "ViewController.h"
#import "CustomNSOperation.h"
#import "BingFaNSOperation.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //[self testNSBlockOperation];
    //[self testSerailNSBlockOperation];
    //[self testNSInvocationOperation];
    //[self testCustomNSOperation];

    //测试并发的自定义NSOperation
    UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setTitle:@"测试并发的自定义NSOperation" forState:UIControlStateNormal];
    button.frame = CGRectMake(20, 20, 200, 40);
    button.backgroundColor = [UIColor brownColor];
    [button addTarget:self action:@selector(onClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
}


/**
 1.提交到 Operation Queues 的任务必须是 NSOperation 对象,operation object 封装了你要执行的工作,以及所需的所有数据
 2.operation queue 总是并发地执行任务,如果想串行执行需要添加依赖
 下面例子演示的是并行执行
 */
-(void) testNSBlockOperation{

    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    NSBlockOperation* theOp = [NSBlockOperation blockOperationWithBlock: ^{
        NSLog(@"24---------testNSBlockOperation  curThread will sleep 3 seconds:%@",[NSThread currentThread]);
        NSDate *date = [NSDate dateWithTimeIntervalSinceNow:3];
        [NSThread sleepUntilDate:date];
        NSLog(@"35---------testNSBlockOperation  curThread:%@  slee end",[NSThread currentThread]);
    }];

    NSBlockOperation* theOp2 = [NSBlockOperation blockOperationWithBlock: ^{
        NSLog(@"36---------testNSBlockOperation  curThread:%@",[NSThread currentThread]);

    }];

    [queue addOperation:theOp];
    [queue addOperation:theOp2];

    //NSOperation 类对象的 isConcurrent 方法 告诉你这个 operation 相对于调用 start 方法的线程,是同步还是异步执 行的

}

/**
 演示例子的串行执行
 */
-(void)testSerailNSBlockOperation{

    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    NSBlockOperation* theOp = [NSBlockOperation blockOperationWithBlock: ^{
        NSLog(@"24---------  curThread will sleep 3 seconds:%@",[NSThread currentThread]);
        // sleep 3秒后的时间
        NSDate *date = [NSDate dateWithTimeIntervalSinceNow:3];
        [NSThread sleepUntilDate:date];
        NSLog(@"35---------  curThread:%@  slee end",[NSThread currentThread]);

    }];
    //[theOp start];    //执行的是在主线程中

    NSBlockOperation* theOp2 = [NSBlockOperation blockOperationWithBlock: ^{
        NSLog(@"36---------  curThread:%@",[NSThread currentThread]);

    }];
   // [theOp2 start];   //执行的是在主线程中
    [theOp2 addDependency:theOp];
    [queue addOperation:theOp];
    [queue addOperation:theOp2];

}

/**
 如果已经现有一个方法,需要并发地执行,就可以直接创
 建 NSInvocationOperation 对象
 */
-(void)testNSInvocationOperation{

    NSInvocationOperation* theOp = [[NSInvocationOperation alloc] initWithTarget:self
                                                                selector:@selector(myTaskMethod:) object:@"liu"];
    [theOp start];  //在主线程测试

}
- (void)myTaskMethod:(id)data {
    NSLog(@"86-------------:%@",data);
}

/**
 测试自定义NSOperation
 */
-(void) testCustomNSOperation{

    CustomNSOperation* opreation = [[CustomNSOperation alloc] initWithData:@"test customOperation"];
    //[opreation start];      //将自定义operation放在 主线程中执行

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

    //将操作任务放到子线程执行
    //[queue addOperation:opreation];


    //当将其加入到队列中,但这样存在一个问题,由于我们没有实现finished属性,所以获取finished属性时只会返回NO,
    //任务加入到队列后不会被队列删除,一直会保存,而且任务执行完成后的回调块也不会执行,
    //所以最好不要只实现一个main方法就交给队列去执行,即使我们没有实现start方法,
    //这里调用start方法以后依旧会执行main方法。这个非并发版本不建议写,好像也没有什么场景需要这样写,反而更加复杂,如果不小心加入到队列中还会产生未知的错误。
    NSLog(@"108--------------:%d",[opreation isFinished]);
}

-(void) onClick:(UIButton*)button{
    [self testBingFaNSOperation];
}

-(void) testBingFaNSOperation{
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    BingFaNSOperation *bingFa = [[BingFaNSOperation alloc] init];
    [queue addOperation:bingFa];
}




- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];

}


@end

自定义NSOpertion:

#import <Foundation/Foundation.h>


/**
 每个 operation 对象至少需要实现以下方法:
    自定义 initialization 方法:初始化,将 operation 对象设置为已知 状态
    自定义 main 方法:执行你的任务

你也可以选择性地实现以下方法:
    main方法中需要调用的其它自定义方法
    Accessor方法:设置和访问operation对象的数据
    dealloc方法:清理operation对象分配的所有内存
    NSCoding 协议的方法:允许 operation 对象 archive 和 unarchive
 */
@interface CustomNSOperation : NSOperation



/**
 本接口主要用来处理

 @param data
 @return 
 */
-(id)initWithData:(id)data;


@end

。m文件:

//
//  CustomNSOperation.m
//  MultiThread
//
//  Created by liuxiaobing on 2018/7/27.
//  Copyright © 2018 liuxiaobing. All rights reserved.
//

#import "CustomNSOperation.h"

@implementation CustomNSOperation

-(id) initWithData:(id)data{
    if (self = [super init]){

    }
    return self;
}


/**
 override  主要用来执行任务的接口,类似java Thread中的run接口
 定义非并发,直接重写这个main方法即可
 */
-(void)main{

    NSLog(@"26-------我是一个自定义的Operation 在这个函数中处理我的异步任务");
//    响应取消事件
//    operation 开始执行之后,会一直执行任务直到完成,或者显式地取 消操作。取消可能在任何时候发生,甚至在 operation 执行之前。尽 管 NSOperation 提供了一个方法,让应用取消一个操作,但是识别出取 消事件则是你的事情。如果 operation 直接终止,可能无法回收所有已 分配的内存或资源。因此 operation 对象需要检测取消事件,并优雅地 退出执行。
//    operation 对象定期地调用 isCancelled 方法,如果返回 YES(表示已 取消),则立即退出执行。不管是自定义NSOperation 子类,还是使用 系统提供的两个具体子类,都需要支持取消。isCancelled 方法本身非常 轻量,可以频繁地调用而不产生大的性能损失。以下地方可能需要调用 isCancelled:
//     在执行任何实际的工作之前
//     在循环的每次迭代过程中,如果每个迭代相对较长可能需要调用
//    多次
//     代码中相对比较容易中止操作的任何地方

//    while(![self isCancelled]){
//        NSLog(@"26-------我是一个自定义的Operation 在这个函数中处理我的异步任务");
//    }
}




/**
 释放本对象的接口,由系统调用
 */
- (void)dealloc {
    NSLog(@"35---------我是一个自定义的Operation,我即将释放");
}

@end

自定义并发的NSOperation

#import <Foundation/Foundation.h>

/**  实现并发需要重载的方法与属性
 方法 描述

 start (必须)所有并发操作都必须覆盖这个方法,以自定义的实现替换 默认行为。手动执行一个操作时,你会调用 start 方法。
 因此你对这 个方法的实现是操作的起点,设置一个线程或其它执行环境,来执 行你的任务。你的实现在任何时候都绝对不能调用 super。


 main (可选)这个方法通常用来实现 operation 对象相关联的任务。尽管 你可以在 start 方法中执行任务,使用 main 来实现任务可以让你的 代码更加清晰地分离设置和任务代码

 isExecuting isFinished
 (必须)并发操作负责设置自己的执行环境,并向外部 client 报告 执行环境的状态。因此并发操作必须维护某些状态信息,以知道是 否正在执行任务,是否已经完成任务。使用这两个方法报告自己的 状态。 这两个方法的实现必须能够在其它多个线程中同时调用。另外这些 方法报告的状态变化时,还需要为相应的 key path 产生适当的 KVO 通知。


 isConcurrent (必须)标识一个操作是否并发 operation,覆盖这个方法并返回 YES

 */



@interface BingFaNSOperation : NSOperation{

    BOOL executing;    //属性通过kvo机制进行实现
    BOOL finished;
}

- (void)completeOperation;







@end

。m文件

#import "BingFaNSOperation.h"

@implementation BingFaNSOperation


- (id)init {
    self = [super init]; if (self) {
        executing = NO;
        finished = NO;
    }
    return self;
}

- (BOOL)isConcurrent {
    return YES;
}
- (BOOL)isExecuting {
    return executing;
}
- (BOOL)isFinished {
    return finished;
}

/**
 (必须)所有并发操作都必须覆盖这个方法,以自定义的实现替换 默认行为。手动执行一个操作时,你会调用 start 方法。
 因此你对这 个方法的实现是操作的起点,设置一个线程或其它执行环境,来执 行你的任务。
 你的实现在任何时候都绝对不能调用 super。
 */
-(void)start{

    // Always check for cancellation before launching the task. if ([self isCancelled])
    if([self isCancelled]){
        // Must move the operation to the finished state if it is canceled.
        [self willChangeValueForKey:@"isFinished"];
        finished = YES;
        [self didChangeValueForKey:@"isFinished"];  //触发 isFinished属性
        return;
    }


    // If the operation is not canceled, begin executing the task.
    [self willChangeValueForKey:@"isExecuting"];
    [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil];
    executing = YES;
    [self didChangeValueForKey:@"isExecuting"];     //触发 isExecuting属性

}

//实现并发本接口是否重载是可选的
-(void)main{
    [self completeOperation];
}

/**
 自定义一个执行完成的方法
 */
-(void) completeOperation{

    [self willChangeValueForKey:@"isFinished"];
    [self willChangeValueForKey:@"isExecuting"];
    executing = NO;
    finished = YES;
    [self didChangeValueForKey:@"isExecuting"];
    [self didChangeValueForKey:@"isFinished"];
}

@end

参考文献:
https://blog.youkuaiyun.com/u014205968/article/details/78323182

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值