常用子类:
NSOperation是一个基类,不应该直接生成NSOperation对象,而是应该用它的子类。
- NSInvocationOperation
- 将特定对象的特定方法封装成NSOperation
- NSBlockOperation
- 将代码块封装成NSOpreation
示例:
创建NSInvocationOperation
NSString* url = @"http://www.xxx.com";
//以self的downloadImageFromURL:方法作为执行体,创建NSOperation
NSInvocationOperation* operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downloadImageFromURL:) object:url];
创建NSBlockOperation
NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock:^{
//执行体
...
}];
常用状态:
可以通过KVO监听NSOperation的状态
- isCancelled
- isAsynchronous
- isExecuting
- isFinished
- isReady
执行任务
创建了一个NSBlockOperation,并且设置好它的block,也就是将要执行的任务。这个任务会在主线程中执行。
调用start方法让NSOperation方法运行起来。start是一个同步方法。
在当前任务状态和依赖关系合适的情况下,启动NSOperation的main方法任务,需要注意缺省实现只是在当前线程运行。如果需要并发执行,子类必须重写这个方法,并且使 - (BOOL)isConcurrent 方法返回YES
let operation = NSBlockOperation { () -> Void in
print(NSThread.currentThread())
}
operation.addExecutionBlock { () -> Void in
print("execution block1 --(NSThread.currentThread())")
}
operation.start()
默认的NSOperation是同步执行的。简单的看一下NSOperation类的定义会发现它有一个只读属性asynchronous
这意味着如果想要异步执行,就需要自定义NSOperation的子类。或者使用NSOperationQueue
取消任务
如果我们有两次网络请求,第二次请求会用到第一次的数据。如果此时网络情况不好,第一次请求超时了,那么第二次请求也没有必要发送了。当然,用户也有可能人为地取消某个NSOperation。
当某个NSOperation被取消时,我们应该尽可能的清除NSOperation内部的数据并且把cancelled和finished设为true,把executing设为false。
//取消某个NSOperation
operation1.cancel()
//取消某个NSOperationQueue剩余的NSOperation
queue.cencelAllOperations()
获取状态
- @property(readonly, getter=isCancelled) BOOL cancelled
- 当前任务状态是否已标记为取消
- @property(readonly, getter=isExecuting) BOOL executing
- 当前任务状态是否已标记为取消
- @property(readonly, getter=isFinished) BOOL finished
- NSOperation任务是否已结束
- @property(readonly, getter=isConcurrent) BOOL concurrent
- @property(readonly, getter=isAsynchronous) BOOL asynchronous
- @property(readonly, getter=isReady) BOOL ready
- NSOperation任务是否已结束
- @property(copy) NSString *name
等待
-
-(void)waitUntilFinished
NSBlockOperation *opB = [NSBlockOperation blockOperationWithBlock:^{ [opA waitUntilFinished]; //opB线程等待直到opA执行结束(正常结束或被取消) [self operate]; }];
设置依赖
依然考虑刚刚所说的两次网络请求的例子。因为第二次请求会用到第一次的数据,所以我们要保证发出第二次请求的时候第一个请求已经执行完。但是我们同时还希望利用到NSOperationQueue的并发特性(因为可能不止这两个任务)。
这时候我们可以设置NSOperation之间的依赖关系。语法非常简洁:
operation2.addDependency(operation1)
需要注意的是NSOperation之间的相互依赖会导致死锁
移除依赖:
- (void)removeDependency:(NSOperation *)operation
优先级
GCD中,任务(block)是没有优先级的,而队列具有优先级。和GCD相反,我们一般考虑NSOperation的优先级
NSOperation有一个NSOperationQueuePriority枚举类型的属性queuePriority
typedef enum : NSInteger {
NSOperationQueuePriorityVeryLow = -8,
NSOperationQueuePriorityLow = -4,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
} NSOperationQueuePriority;