5

我正在开发的应用程序会定期从应用程序服务器刷新其本地数据缓存(10 多个请求,每个请求都需要相当长的时间)。我目前正在异步运行这些请求,以免阻塞 UI 线程。beginBackgroundTaskWithExpirationHandler由于这些请求确实需要一段时间来处理然后加载到核心数据中,我想利用NSOperationQueue.

在我将所有请求添加到操作队列后,我使用waitUntilAllOperationsAreFinishedto 阻塞直到所有操作完成(这不在主线程上)。我在原型中看到的问题是,当我运行应用程序并立即将其后台运行(按主页按钮)时,waitUntilAllOperationsAreFinished即使在所有操作完成后仍然被阻止......但是一旦我再次打开应用程序,处理程序完成。如果我运行该应用程序并让它保持在前台,一切都会很好。在我的实际应用程序中,这种行为似乎并不总是发生,但使用下面的示例代码,它似乎:

#import "ViewController.h"

@interface ViewController ()

@property (assign, nonatomic) UIBackgroundTaskIdentifier task;
@property (strong, nonatomic) NSOperationQueue *queue;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self performSelectorInBackground:@selector(queueItUp) withObject:nil];
}

- (void)queueItUp {
    UIApplication *application = [UIApplication sharedApplication];

    self.queue = [[NSOperationQueue alloc] init];
    self.task = [application beginBackgroundTaskWithExpirationHandler:^{
        NSLog(@"Took too long!");

        [self.queue cancelAllOperations];
        [application endBackgroundTask:self.task];
        self.task = UIBackgroundTaskInvalid;
    }];

    for (int i = 0; i < 5; i++) {
        [self.queue addOperationWithBlock:^{
            [NSThread sleepForTimeInterval:3];
            NSLog(@"Finished operation.");
        }];
    }


    NSLog(@"Waiting until all operations are finished.");

    [self.queue waitUntilAllOperationsAreFinished];

    [application endBackgroundTask:self.task];
    self.task = UIBackgroundTaskInvalid;

    NSLog(@"All done :)");
}

@end

我究竟做错了什么?

谢谢

4

2 回答 2

4

您的示例代码在 iPhone 或模拟器上的 iOS 6.1 上的任何时候都不会永久阻塞。在 line 处放一个断点[application endBackgroundTask:self.task];,你每次都会命中它。

您看到的行为是因为您在告诉应用程序结束后台任务后在后台登录。我不确定确切的细节,但日志以某种方式排队,以便在您的应用程序恢复到前台时打印到控制台。可能是线程执行被暂停的情况。

如果您NSLog(@"All done");在调用 之前移动到endBackgroundTask:,您将看到记录的输出。

于 2013-04-02T19:48:20.010 回答
1

使用您的示例代码,操作完成得很好。你挂在上面NSLog(@"All done :)");。您的队列仍然存在并且没有挂起的操作,但是您可能不再有活动的运行循环,并且主线程在您和后台被阻塞。由于您已完成待处理的后台操作,因此您已被阻止。当您恢复您的应用程序时,它会从中断的地方继续。如果你这样做:

    [[self queue] addOperationWithBlock:^{
        NSLog(@"All done :)");
    }];

行为应该更加明显。它正在做你告诉它做的事情。

你有一堆操作在排队,你已经调用了waitUntilAllOperationsAreFinished. 当他们完成时,您将被阻止在后台。

当这组操作完成时,您似乎正在尝试执行某些操作。NSOperation 提供了具有允许您构建这种行为的依赖项和完成块的能力。您可以对操作进行分组并设置在您的操作组完成时运行的完成块或操作。并发编程指南中涵盖了其中一些内容

于 2013-04-02T19:12:43.470 回答