Pet*_*isu 17 cocoa asynchronous nsoperation nsoperationqueue
我需要将异步操作放入操作队列,但是,它们需要在另一个之后执行
self.operationQueue = [NSOperationQueue new];
self.operationQueue.maxConcurrentOperationCount = 1;
[self.operationQueue addOperationWithBlock:^{
// this is asynchronous
[peripheral1 connectWithCompletion:^(NSError *error) {
}];
}];
[self.operationQueue addOperationWithBlock:^{
// this is asynchronous
[peripheral2 connectWithCompletion:^(NSError *error) {
}];
}];
Run Code Online (Sandbox Code Playgroud)
问题是,由于peripheralN connectWithCompletion是异步的,队列中的操作结束而下一个执行,我需要模拟,peripheralN connectWithCompletion是同步的并等待操作结束,直到异步块执行
所以我需要这样的行为,只使用操作队列
[peripheral1 connectWithCompletion:^(NSError *error) {
[peripheral2 connectWithCompletion:^(NSError *error) {
}];
}];
Run Code Online (Sandbox Code Playgroud)
Mik*_*e S 24
NSBlockOperation无法处理异步操作,但创建一个子类并不是那么难NSOperation......
基本上,您需要创建一个NSOperation带有一个块的块,该块将另一个块作为完成处理程序.该块可以像这样定义:
typedef void(^AsyncBlock)(dispatch_block_t completionHandler);
Run Code Online (Sandbox Code Playgroud)
然后,在你的NSOperation子类的start方法中,你需要调用你的AsyncBlock传递它将dispatch_block_t在执行完成时调用它.你还需要确保留KVO兼容NSOperation的isFinished和isExecuting特性(至少)(见KVO兼容属性的NSOperation文档); 这是允许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"];
});
}
Run Code Online (Sandbox Code Playgroud)
请注意,_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();
}];
}];
Run Code Online (Sandbox Code Playgroud)
我在这里整理了一个简单版本的要点: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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
我做的是分别[myQueue setSuspended:YES]和[myQueue setSuspended:NO]之前和之后一起玩.
例如:
[myQueue addOperationWithBlock:^{
[myQueue setSuspended:YES];
[someBackendService doSomeAsyncJobWithCompletionBlock:^{
callback(YES, nil);
[myQueue setSuspended:NO];
});
}];
Run Code Online (Sandbox Code Playgroud)
实现的效果是队列在异步任务之前暂停,因此即使返回操作块,它也只会在maxConcurrentOperationCount调用异步任务的完成块时启动下一个操作(当然要受制于此).
| 归档时间: |
|
| 查看次数: |
4736 次 |
| 最近记录: |