Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c NSOperationQueue WaitUntillall操作已完成在后台不工作_Objective C_Nsoperation_Nsoperationqueue - Fatal编程技术网

Objective c NSOperationQueue WaitUntillall操作已完成在后台不工作

Objective c NSOperationQueue WaitUntillall操作已完成在后台不工作,objective-c,nsoperation,nsoperationqueue,Objective C,Nsoperation,Nsoperationqueue,我正在开发的应用程序定期从应用服务器刷新其本地数据缓存(10多个请求,每个请求都需要相当长的时间)。我目前正在异步运行这些请求,以便不阻塞UI线程。由于这些请求确实需要一段时间来处理并加载到核心数据中,因此我想利用beginBackgroundTaskWithExpirationHandler和NSOperationQueue的依赖操作行为 将所有请求添加到操作队列后,我将使用waitUntillalOperationsRefiefined阻塞,直到所有操作都完成(这不在主线程上)。我在原型中看

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

将所有请求添加到操作队列后,我将使用
waitUntillalOperationsRefiefined
阻塞,直到所有操作都完成(这不在主线程上)。我在原型中看到的问题是,当我运行应用程序并立即将其设置为背景(按home按钮)时,
WaitUntillalOperationsRefiefined
即使在所有操作完成后仍会被阻止。。。但只要我再次打开应用程序,处理程序就会完成。如果我运行应用程序,让它保持在前台,一切都会顺利完成。在我的实际应用程序中,这种行为似乎并不总是发生,但通过下面的示例代码,它似乎是:

#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
#导入“ViewController.h”
@界面视图控制器()
@属性(赋值,非原子)UIBackgroundTaskIdentifier任务;
@属性(强,非原子)NSOperationQueue*队列;
@结束
@实现视图控制器
-(无效)viewDidLoad
{
[超级视图下载];
[self-performSelectorInBackground:@selector(queueItUp)with object:nil];
}
-(void)queueItUp{
UIApplication*application=[UIApplication sharedApplication];
self.queue=[[NSOperationQueue alloc]init];
self.task=[应用程序beginBackgroundTaskWithExpirationHandler:^{
NSLog(@“花了太长时间!”);
[自队列取消所有操作];
[应用程序endBackgroundTask:self.task];
self.task=ui背景任务无效;
}];
对于(int i=0;i<5;i++){
[self.queue addOperationWithBlock:^{
[NSThread sleepForTimeInterval:3];
NSLog(@“已完成操作”);
}];
}
NSLog(@“等待所有操作完成”);
[self.queue waituntlalloperations完成];
[应用程序endBackgroundTask:self.task];
self.task=ui背景任务无效;
NSLog(@“全部完成:”);
}
@结束
我做错了什么


感谢使用示例代码,操作完成得很好。它位于
NSLog(@“全部完成:”)上你被绞死了。您的队列仍然存在,并且没有挂起的操作,但是您可能不再有活动的runloop,并且主线程在您和后台被阻塞。由于您已经完成了挂起的后台操作,因此被阻止。当你继续你的应用程序时,它会在停止的地方继续。如果您这样做:

    [[self queue] addOperationWithBlock:^{
        NSLog(@"All done :)");
    }];
这种行为应该更加明显。它正在做你让它做的事情

您有一组操作排队,并且调用了
waituntlalloperationsarefiefined
。当它们完成时,您将在后台被阻止


这组操作完成后,您似乎正在尝试执行某些操作。NSOperation提供了具有依赖性和完成块的能力,允许您构造这种行为。您可以对操作进行分组,并设置完成块或操作组完成时运行的操作。在iPhone或模拟器的iOS 6.1上,您的示例代码在任何时候都不会永久阻塞。在
[application endBackgroundTask:self.task]行中放置一个断点,您每次都会点击它

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


如果移动
NSLog(@“全部完成”)
在调用
endBackgroundTask:
之前,您将看到记录的输出。

Hmm。。。我想我计划做的是使用
waitUntillalOperationsRefiefined
作为某种屏障/关卡,一旦通过该关卡,执行一个完成操作(在本例中,将所有下载的数据加载到核心数据中)。你是不是建议我创建另一个操作,它依赖于所有其他操作,来执行完成操作?因此,甚至不需要使用
waitUntillalOperationsDefined
?您可以这样做,您可以执行将所有其他操作作为依赖项的单个操作,您可以执行包含其他操作的操作,等等。或者如果操作不是并发的,将操作安排为队列中执行完成操作的最后一项。您仍然需要使用
waitUntilalAllOperations完成
,以确保队列在后台运行。在调用之前,您只需将完成操作(无论是什么)放入队列中即可。如果后台任务已经启动,为什么在这种情况下仍需要使用
WaitUntilalAllOperationsDefiefined
?在所有排队操作完成之前,您的队列仍然可以挂起。