gpt4 book ai didi

cocoa - NSOperation 等待异步 block 执行

转载 作者:行者123 更新时间:2023-12-03 16:01:58 24 4
gpt4 key购买 nike

我需要将异步操作放入操作队列中,但是,它们需要在另一个操作之后执行

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是异步的,队列中的操作结束并执行下一个,但是我需要模拟,peripheralN connectWithCompletion是同步的并等待操作结束,直到异步 block 执行

所以我需要这样的行为,仅使用操作队列

    [peripheral1 connectWithCompletion:^(NSError *error) {

[peripheral2 connectWithCompletion:^(NSError *error) {

}];

}];

最佳答案

NSBlockOperation 无法处理异步操作,但创建可以...的 NSOperation 子类并不那么困难

基本上,您需要创建一个 NSOperation,它采用一个 block ,该 block 将 另一个 block 作为完成处理程序。该 block 可以这样定义:

typedef void(^AsyncBlock)(dispatch_block_t completionHandler);

然后,在您的 NSOperation 子类的 start 方法中,您需要调用 AsyncBlock 并向其传递 dispatch_block_t执行完成后将被调用。您还需要确保保持 KVONSOperationisFinishedisExecuting 属性(至少)兼容(请参阅 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 需要在子类中的某个位置定义,并且您需要重写 isExecutingisFinished 属性以返回正确的值。

如果将所有这些放在一起,以及一个采用 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

关于cocoa - NSOperation 等待异步 block 执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26889861/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com