NSBlockOperation 无法处理异步操作,但创建一个可以...的NSOperation 子类并不是那么难...
基本上,您需要创建一个NSOperation,它接受一个将另一个 块作为完成处理程序的块。块可以这样定义:
typedef void(^AsyncBlock)(dispatch_block_t completionHandler);
然后,在您的NSOperation 子类的start 方法中,您需要调用您的AsyncBlock,并传递给它一个dispatch_block_t,它将在执行完成时调用。您还需要确保KVO 符合NSOperation 的isFinished 和isExecuting 属性(至少)(参见NSOperation 文档中的KVO-Compliant Properties);这就是允许NSOperationQueue 等待异步操作完成的原因。
类似这样的:
- (void)start {
[self willChangeValueForKey:@"isExecuting"];
_executing = YES;
[self didChangeValueForKey:@"isExecuting"];
self.block(^{
[self willChangeValueForKey:@"isExecuting"];
_executing = NO;
[self didChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
_finished = YES;
[self didChangeValueForKey:@"isFinished"];
});
}
请注意,_executing 和 _finished 需要在您的子类中的某个位置进行定义,并且您需要覆盖 isExecuting 和 isFinished 属性以返回正确的值。
如果你把所有这些放在一起,连同一个接受你的 AsyncBlock 的初始化程序,那么你可以像这样将你的操作添加到队列中:
[self.operationQueue addOperationWithBlock:^(dispatch_block_t completionHandler) {
[peripheral1 connectWithCompletion:^(NSError *error) {
// call completionHandler when the operation is done
completionHandler();
}];
}];
[self.operationQueue addOperationWithBlock:^(dispatch_block_t completionHandler) {
[peripheral2 connectWithCompletion:^(NSError *error) {
// call completionHandler when the operation is done
completionHandler();
}];
}];
我在这里整理了一个简单版本的要点:AsyncOperationBlock。
这只是最低限度的实现,但它应该可以工作(例如,如果 isCancelled 也实现了,那就太好了)。
为了完整起见,复制到这里:
AsyncBlockOperation.h:
#import <Foundation/Foundation.h>
typedef void(^AsyncBlock)(dispatch_block_t completionHandler);
@interface AsyncBlockOperation : NSOperation
@property (nonatomic, readonly, copy) AsyncBlock block;
+ (instancetype)asyncBlockOperationWithBlock:(AsyncBlock)block;
- (instancetype)initWithAsyncBlock:(AsyncBlock)block;
@end
@interface NSOperationQueue (AsyncBlockOperation)
- (void)addAsyncOperationWithBlock:(AsyncBlock)block;
@end
AsyncBlockOperation.m:
#import "AsyncBlockOperation.h"
@interface AsyncBlockOperation () {
BOOL _finished;
BOOL _executing;
}
@property (nonatomic, copy) AsyncBlock block;
@end
@implementation AsyncBlockOperation
+ (instancetype)asyncBlockOperationWithBlock:(AsyncBlock)block {
return [[AsyncBlockOperation alloc] initWithAsyncBlock:block];
}
- (instancetype)initWithAsyncBlock:(AsyncBlock)block {
if (self = [super init]) {
self.block = block;
}
return self;
}
- (void)start {
[self willChangeValueForKey:@"isExecuting"];
_executing = YES;
[self didChangeValueForKey:@"isExecuting"];
self.block(^{
[self willChangeValueForKey:@"isExecuting"];
_executing = NO;
[self didChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
_finished = YES;
[self didChangeValueForKey:@"isFinished"];
});
}
- (BOOL)isFinished {
return _finished;
}
- (BOOL)isExecuting {
return _executing;
}
- (BOOL)isAsynchronous {
return YES;
}
@end
@implementation NSOperationQueue (AsyncBlockOperation)
- (void)addAsyncOperationWithBlock:(AsyncBlock)block {
[self addOperation:[AsyncBlockOperation asyncBlockOperationWithBlock:block]];
}
@end