【问题标题】:How to properly execute performFetchWithCompletionHandler with multiple blocks inside如何正确执行内部有多个块的 performFetchWithCompletionHandler
【发布时间】:2025-11-21 16:40:03
【问题描述】:

我正在使用后台获取方法performFetchWithCompletionHandler 来更新一些用户数据。但是,这些过程相当复杂,并且包含块语句,因此它们不会同步执行。

我担心的是我总是返回completionHandler(UIBackgroundFetchResultNewData);

-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    NSLog(@"Start background data fetch");

    // Update data -- this method contains various blocks inside
    [GETDataRequest updateUserDataWithUser: user];

    // Update images -- this method contains various blocks inside
    [GETImagesRequest updateUserImagesWithUser: user];

    NSLog(@"Background Data Fetch completed");
    completionHandler(UIBackgroundFetchResultNewData);
}

根据this post,关于completionHandler(UIBackgroundFetchResultNewData),提到了以下内容:

你必须调用它来让 iOS 知道你后台获取的结果是什么。它使用此信息来安排未来的后台提取。如果您忽略此操作,操作系统可能会延迟将来的后台提取。不调用此处理程序的后果可能包括完全终止您的应用程序。

正如您在此处看到的,我总是说它是成功的,不管它是否真的成功。回答者对我的情况是这样说的:

...您应该仅在获取实际完成时才调用完成处理程序。否则,iOS 可能会在连接完成之前让您的应用程序重新进入睡眠状态,并且应用程序实际上不应该能够确定 UIBackgroundFetchResultNewData 与 UIBackgroundFetchResultNoData 或 UIBackgroundFetchResultFailed 直到那时为止。你怎么知道你的连接会成功?

我正在做的事情真的有问题吗?它真的会切断更新吗?如果它会产生意想不到的结果,那么解决这个烂摊子的办法是什么?我提到的问题的答案对我来说不够清楚。我曾尝试使用块变量使其发挥应有的作用,但没有成功。非常感谢。

【问题讨论】:

  • "只有当你的 fetch 真正完成时你才应该调用完成处理程序" 这完全是错误的。恰好相反。如果你不回调它并快速回调它,你将永远不会再获得后台抓取机会;系统会给你“黑球”。

标签: objective-c


【解决方案1】:

您使用的代码用于后台获取刷新功能,通过此功能,您可以通过将系统时间间隔设置为最小来快速刷新您的应用程序。该服务在委托方法 performFetchWithCompletionHandler 中可用,持续时间为 30 秒。您需要相应地管理您的代码以获得更新的结果,然后根据您的结果,您需要调用适当的完成处理程序块。 如果你有长时间运行的后台任务,我会更喜欢使用 NSURLSessions 的后台获取服务。

【讨论】: