设为首页 加入收藏

TOP

创建一个支持异步操作的operation
2017-10-13 09:54:04 】 浏览:3011
Tags:创建 一个 支持 异步 操作 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)willChangeva lueForKey:(NSString *)key;
- (void)didChangeva lueForKey:(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 willChangeva lueForKey:@"isReady"];
        self.state = MyOperationStateReady;
        [self willChangeva lueForKey:@"isReady"];
    }
    return self;
}

- (void)start
{
    [self.lock lock];
    if (!self.finished && self.state == MyOperationStateReady) {
// 触发
isExecuting属性的KVO观察者,这样系统就知道这个operation已经开始执行了
[self willChangeva lueForKey:@"isExecuting"]; self.state = MyOperationStateExecuting; [self didChangeva lueForKey:@"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 willChangeva lueForKey:@"isFinished"]; 
self.state
= MyOperationStateFinished;
[self didChangeva lueForKey:
@"isFinished"];
[self.
lock unlock];
}
@end

 

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇IOS 杂笔-8(loadView、viewDidL.. 下一篇创建一个支持异步操作的operation

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目