【问题标题】:How to check if NSOperationQueue is finished and if any operation failed?如何检查 NSOperationQueue 是否完成以及是否有任何操作失败?
【发布时间】:2011-10-18 10:19:27
【问题描述】:

我正在尝试在后台解析一些 XML 文件,以便 UI 不会冻结。我必须检查两件事:

  • NSOperationQueue 完成了吗?
  • NSOperation - 解析失败了吗?

我有一个继承 NSOperation 的类,如果解析失败,则会调用一个委托。队列中的操作仅限于同时进行一项。

我的问题是我不能依赖在我得到队列完成消息之前执行失败消息的事实。有时我在收到完成的消息之前没有收到失败的消息。然后,例如,我有这个命令:

操作 1 成功 操作 2 成功 操作队列完成 操作 3 失败

所有消息都发送到主线程。在我收到完成的消息后,我想继续我的代码,但前提是所有操作都成功。如何处理队列完成后调用委托消息的问题。

这是我的代码的一些部分:

//XMLOperation.m
- (void)main {    
    NSLog(@"Operation started");

    if ([self parseXML]) {
            [self performSelectorOnMainThread:@selector(finishedXMLParsing) withObject:nil waitUntilDone:NO];
        } else {
            [self performSelectorOnMainThread:@selector(failedXMLParsing) withObject:nil waitUntilDone:NO];
        }
    }
    NSLog(@"Operation finished");
}


//StartController.m
[self.xmlParseQueue addObserver:self forKeyPath:@"operations" options:0 context:NULL];

...

- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
                         change:(NSDictionary *)change context:(void *)context
{
    if (object == self.xmlParseQueue && [keyPath isEqualToString:@"operations"]) {
        if ([self.xmlParseQueue.operations count] == 0) {
            // Do something here when your queue has completed
            NSLog(@"queue has completed");
        }
    }
    else {
        [super observeValueForKeyPath:keyPath ofObject:object 
                               change:change context:context];
    }
}

【问题讨论】:

标签: objective-c multithreading nsoperation nsoperationqueue


【解决方案1】:

这可能是因为您的队列的operations 属性的 KVO 通知不一定在主线程上传递,而您的完成/失败通知是。

您应该确保在主线程上也执行完成通知,以便定义通知的顺序。

【讨论】:

  • 与您在操作的main 方法中执行此操作的方式相同,通过在主线程上完成队列时执行您执行的“某事”。
  • 我已经验证了KVO的方案,但是失败了,当最后一个操作将被执行但还没有执行时,操作队列的操作数组已经移除了它,所以它不起作用。
【解决方案2】:

继续这个问题并在此处粘贴我的代码解决方案。

void RunInMainThread(void (^block)(void))
{
    if (!block) {
        return;
    }

    if ([NSThread isMainThread]) {
        block();
    } else {
        dispatch_async(dispatch_get_main_queue(), block);
    }
}

@interface MyOperationQueue : NSOperationQueue

@property (nonatomic, assign) NSUInteger totalCount;
@property (nonatomic, copy) dispatch_block_t allOperationCompletionBlock;

@end

@implementation MyOperationQueue

- (void)addOperation:(NSOperation *)op
{
    [super addOperation:op];
    __weak typeof(self) weakSelf = self;

    self.totalCount++;
    DDLogVerbose(@"Added a operation, total: %ld operation(s).", self.totalCount);

    op.completionBlock = ^ {
        weakSelf.totalCount--;
        DDLogVerbose(@"Finished a operation, left: %ld operation(s).", weakSelf.totalCount);

        if (weakSelf.totalCount == 0) {
            if (weakSelf.allOperationCompletionBlock) {
                RunInMainThread(weakSelf.allOperationCompletionBlock);
            }
        }
    };
}

@结束

【讨论】:

    猜你喜欢
    • 2018-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-30
    • 1970-01-01
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多