创建一个支持异步操作的operation

NSOperationQueue时iOS中常用的任务调度机制。在创建一个复杂任务的时候,我们通常都需要编写NSOperation的子类。在大部分情况下,重写main方法就可以满足要求。main方法执行完毕后,系统就会认为这个operation完成了。

 

有时候情况并没有这么简单。我们需要在operation中调用异步的API,这个API会通过一个block或者代理通知我们结果。这时只靠覆盖main方法就显得力不从心了。因为异步API尚未执行完毕,main方法并不会等待任务执行完毕,而是立即返回,系统就认为operation已经完成了。

 

怎么解决这个问题呢?我想到AFNetworking中有同样的案例,于是参考了其中的实现,设计了一个基于异步任务的operation。

 

我们需要覆盖start方法。这个方法的作用有点类似于main方法,在这里完成具体的任务。那么系统怎么知道我们的任务开始执行,或者完成了呢?系统会通过KVO的形式,监听operation的一些属性。我们可以重新实现这些属性,这样系统就可以监听operation执行的状态。

我们需要重新实现这些属性:

@property (readonly, getter=isReady) BOOL ready;
@property (readonly, getter=isExecuting) BOOL executing;
@property (readonly, getter=isFinished) BOOL finished;

 

它们都是只读属性。我们可以简单的重写它们,返回我们想要的值。但是,如何通知KVO系统它们的值发生了变化呢?

NSObject的这一对方法能够帮助我们,可以利用它们手动通知系统某个属性发生了变化。

- (void)willChangeValueForKey:(NSString *)key;
- (void)didChangeValueForKey:(NSString *)key;

 

下面就是完整的代码。这里只用了一个NSTimer模拟一个异步的任务。在state变化时,我们需要通知KVO系统operation的状态发生了变化。这一步很重要,我刚开始忽略了手动通知KVO,导致任务永远无法完成(即使start中的任务全部执行完毕)。

typedef NS_ENUM(NSInteger, MyOperationState) {
    MyOperationStateReady,
    MyOperationStateExecuting,
    MyOperationStateFinished
};

@interface MyOperation : NSOperation

@property (nonatomic, strong) NSTimer *exeTimer;
@property (nonatomic, assign) MyOperationState state; // 用来记录operation的状态
@property (nonatomic, strong) NSLock *lock; // 加锁保证线程安全

@end

@implementation MyOperation

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.lock = [NSLock new];
        [self willChangeValueForKey:@"isReady"];
        self.state = MyOperationStateReady;
        [self willChangeValueForKey:@"isReady"];
    }
    return self;
}

- (void)start
{
    [self.lock lock];
    if (!self.finished && self.state == MyOperationStateReady) {
// 触发
isExecuting属性的KVO观察者,这样系统就知道这个operation已经开始执行了
[self willChangeValueForKey:@"isExecuting"]; self.state = MyOperationStateExecuting; [self didChangeValueForKey:@"isExecuting"];
        // 这里用一个timer模拟一个耗时的任务
        self.exeTimer = [NSTimer timerWithTimeInterval:5 target:self selector:@selector(finish) userInfo:nil repeats:NO];
        [[NSRunLoop mainRunLoop] addTimer:self.exeTimer forMode:NSRunLoopCommonModes];
    }
    [self.lock unlock];
}

- (void)cancel
{
    [self.lock lock];
    if (!self.isFinished && !self.cancelled) {
        [super cancel];
        [self.exeTimer invalidate];
    }
    [self.lock unlock];
}

- (BOOL)isReady
{
    return self.state == MyOperationStateReady;
}

- (BOOL)isExecuting
{
    return self.state == MyOperationStateExecuting;
}

- (BOOL)isFinished
{
    return self.state == MyOperationStateFinished;
}

- (BOOL)isAsynchronous
{
    return YES;
}

- (BOOL)isConcurrent
{
    return YES;
}

- (void)finish
{
    [self.lock lock];

// 触发isFinished属性的KVO观察者,这样系统就知道这个operation已经执行完毕
    [self willChangeValueForKey:@"isFinished"]; 
self.state = MyOperationStateFinished;
[self didChangeValueForKey:@"isFinished"];
[self.lock unlock];
}
@end

 

转载于:https://www.cnblogs.com/jiuzhou/p/5299535.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值