如何检查 NSOperationQueue 是否完成以及是否有操作失败?

发布于 2024-12-10 15:53:41 字数 1491 浏览 0 评论 0原文

我正在尝试在后台解析一些 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];
    }
}

I'm trying to parse some XML files in the background so that the UI doesn't freeze. I have to check two things:

  • NSOperationQueue is finished?
  • NSOperation - parsing did fail?

I have a class that subclasses NSOperation and a delegate is called if the parsing failed. Operations in the queue are limited to one simultaneously.

My problem is that I can't rely on the fact that the failed message is executed before I get the queue did finish message. Sometimes I don't get a failed message before I get the finished message. Then, for example, I have this order:

Operation 1 Successful
Operation 2 Successful
OperationQueue finished
Operation 3 Failed

All messages are sent to the main thread. After I get the finished message I want to proceed in my code, but only if all operations were successful. How can I handle the problem that the delegate message is called after my queue is finished.

This are some parts of my code:

//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];
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

妳是的陽光 2024-12-17 15:53:41

发生这种情况的原因可能是,队列的操作属性的 KVO 通知不一定在主线程上传递,而已完成/失败的通知则在主线程上传递。

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

This probably happens because your KVO notification for the operations property of the queue is not necessarily delivered on the main thread while your finished/failed notifications are.

You should ensure that the completion notification is performed on the main thread as well, so that the order of your notifications is defined.

眼泪淡了忧伤 2024-12-17 15:53:41

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

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);
            }
        }
    };
}

@结尾

Resume this question and paste my code solution here.

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);
            }
        }
    };
}

@end

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文