NSOperation等待直到异步块执行 [英] NSOperation wait until asynchronous block executes

查看:182
本文介绍了NSOperation等待直到异步块执行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要将异步操作放入操作队列,但是,他们需要在另一个

i need to put asynchronous operations into an operation queue, however, they need to execute on after the other

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) {

    }];

}];

问题是,由于peripheralN connectWithCompletion是异步的,队列中的操作结束, ,我需要然而模拟,外围N connectWithCompletion是同步的,并等待操作结束,直到异步块执行

the problem is, since peripheralN connectWithCompletion is asynchronous, the operation in queue is ended and the next is executed, i would need however simulate, that peripheralN connectWithCompletion is synchronous and wait with the end of operation, till the asynchronous block executes

所以我需要一个这样的行为,只有使用操作队列

so i would need a behaviour like this, only using the operation queue

    [peripheral1 connectWithCompletion:^(NSError *error) {

            [peripheral2 connectWithCompletion:^(NSError *error) {

            }];

    }];


推荐答案

NSBlockOperation 不能处理异步操作,但是不是很难创建 NSOperation 的子类,可以...

NSBlockOperation can't handle asynchronous operations, but it's not all that hard to create a subclass of NSOperation that can...

基本上,你需要创建一个 NSOperation ,它接受一个块,将另一个块作为完成处理程序。该块可以这样定义:

Basically, you need to create an NSOperation that takes a block that takes another block as a completion handler. The block could be defined like this:

typedef void(^AsyncBlock)(dispatch_block_t completionHandler);

然后,在 NSOperation 子类的 start 方法,你需要调用 AsyncBlock 传递 dispatch_block_t 当它完成执行时将被调用。您还需要确保保留 KVO 符合 NSOperation isFinished isExecuting 属性(至少)(请参阅 KVO-在 NSOperation 文档中的属性;这是允许 NSOperationQueue 等待,直到你的异步操作完成。

Then, in your NSOperation subclass's start method, you need to call your AsyncBlock passing it a dispatch_block_t that will be called when it's done executing. You also need to be sure to stay KVO compliant with NSOperation's isFinished and isExecuting properties (at minimum) (see KVO-Compliant Properties in the NSOperation docs); this is what allows the NSOperationQueue to wait until your asynchronous operation is complete.

这样:

- (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 属性返回正确的值。

Note that _executing and _finished will need to be defined in your subclass somewhere, and you'll need to override isExecuting and isFinished properties to return the correct values.

code> AsyncBlock ,你可以像这样将你的操作添加到队列:

If you put all that together, along with an initializer that takes your AsyncBlock, then you can add your operations to the queue like this:

[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 其中也实现,例如)。


I put together a gist of a simple version of this here: AsyncOperationBlock. It's only a minimum implementation, but it should work (it would be nice if isCancelled where also implemented, for example).

为完整性而在此复制:

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

这篇关于NSOperation等待直到异步块执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆