【问题标题】:Objective-c Long Running Task Thread ConfusionObjective-c 长时间运行的任务线程混乱
【发布时间】:2014-01-29 19:50:05
【问题描述】:

我的应用程序需要执行一些与互联网相关的操作,然后在我将应用程序发送到后台时弹出该视图。然后根视图控制器获取一些数据并更新集合视图。您知道如何解决与上述操作相关的以下问题(顺便说一下,我使用本地通知来启动该过程):

1) UI 相关操作(弹出当前视图控制器)似乎在后台失败。

2) 当我将视图弹出到根视图控制器时,根视图有一些 nsurlconnection 将数据发送到其委托。由于长时间运行的任务在全局队列中运行,nsurlconnection 似乎无法向其委托发送任何信息。

我在这个过程中使用以下代码:

   UIBackgroundTaskIdentifier __block bgTask;
   UIApplication  *app = [UIApplication sharedApplication];
   bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
         [app endBackgroundTask:bgTask]; 
         bgTask = UIBackgroundTaskInvalid;
    }];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
         [self performOperation];
         NSLog(@"Operation finished");
     });

【问题讨论】:

  • “UI 相关操作(弹出当前视图控制器)似乎在后台失败。”如果您在后台,则没有 UI。这就是(部分)在后台意味着什么。您需要重新考虑整个架构。
  • 谢谢你帮我节省了很多时间。

标签: objective-c multithreading objective-c-blocks background-process long-running-processes


【解决方案1】:

正如 matt 所指出的,当应用程序在后台时,您不能执行诸如弹出视图控制器之类的 UI 操作。当应用返回前台时(例如,用户再次点击图标),可能会发生弹出(如果应用在此期间没有完全终止)。

我认为马特的观察回答了您的第二个问题。如果没有,请澄清你的意思。但是UIBackgroundTaskIdentifier 的这种使用并不关心您使用的是全局队列还是自定义队列或其他任何东西。唯一的限制是某些 UI 操作不会发生,因此任何依赖于 viewDidAppear 的操作都不会发生。

顺便说一句,我想指出您确实想在执行任务的代码完成时调用endBackgroundTask,而您的代码示例似乎没有这样做。请参阅iOS 应用程序编程指南的应用程序状态和多任务一章的Executing a Finite-Length Task in the Background

因此,您可能会执行以下操作:

UIApplication *app = [UIApplication sharedApplication];

UIBackgroundTaskIdentifier __block bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
    NSLog(@"Operation did not finish!!!");

    [app endBackgroundTask:bgTask]; 
    bgTask = UIBackgroundTaskInvalid;
}];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [self performOperation];
    NSLog(@"Operation finished");

    if (bgTask != UIBackgroundTaskInvalid) {
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }
});

【讨论】:

  • 非常抱歉,您错了。调用endBackgroundTask: 正是您在beginBackgroundTaskWithExpirationHandler: 中所做的事情。实际上,通常所有都是你在那儿做的。如您所知,此处理程序表达的不是任务,而是如果您的时间在任务中间到期时您将做什么 - 在这种情况下调用endBackgroundTask: 正是您必须做的,或者您的应用程序将在后台立即终止。误导 OP 不相信是非常糟糕的。
  • OP 代码的结构是错误的,但不是您建议的方式。他应该在到期处理程序 中调用endBackgroundTask: both 在实际任务结束时。正确的例子见我的书:apeth.com/iOSBook/ch38.html#_threads_and_app_backgrounding
  • @matt 我关注的是当他的后台任务完成时他没有调用endBackgroundTask(导致后台会话总是超时,这是不必要的),而不是担心应用程序,当他有一个真正的超时。我已经相应地修改了我的答案。谢谢!
猜你喜欢
  • 2020-05-13
  • 1970-01-01
  • 2017-10-22
  • 1970-01-01
  • 2015-07-06
  • 1970-01-01
  • 2013-04-21
  • 1970-01-01
  • 2012-08-13
相关资源
最近更新 更多