You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS15与iOS16中BackgroundFetch崩溃问题的修复咨询

iOS15与iOS16中的BackgroundFetch崩溃问题

崩溃日志

Monitor Type:    Mach Exception
Exception Type:  EXC_BREAKPOINT (SIGTRAP)
Exception Codes: KERN_INVALID_ADDRESS at 0x00000001df8354b0
Crashed Thread:  0

Pthread id: 23896613
Thread 0 Crashed:
0   BaseBoard                       -[_BSActionResponder action_sendResponse:] + 528
1   BaseBoard                       -[_BSActionResponder action_sendResponse:] + 520
2   BaseBoard                       -[BSAction sendResponse:] + 76
3   UIKitServices                   -[UISFetchContentInBackgroundAction sendResponse:] + 100
4   UIKitCore                       __91-[UIApplication _handleNonLaunchSpecificActions:forScene:withTransitionContext:completion:]_block_invoke_3 + 60
5   UIKitCore                       -[_UIAfterCACommitBlock run] + 72
6   UIKitCore                       -[_UIAfterCACommitQueue flush] + 176
7   UIKitCore                       _runAfterCACommitDeferredBlocks + 496
8   UIKitCore                       _cleanUpAfterCAFlushAndRunDeferredBlocks + 108
9   UIKitCore                       _UIApplicationFlushCATransaction + 72
10  UIKitCore                       _UIUpdateSequenceRun + 84
11  UIKitCore                       schedulerStepScheduledMainSection + 172
12  UIKitCore                       runloopSourceCallback + 92
13  CoreFoundation                  __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
14  CoreFoundation                  __CFRunLoopDoSource0 + 176
15  CoreFoundation                  __CFRunLoopDoSources0 + 244
16  CoreFoundation                  __CFRunLoopRun + 836
17  CoreFoundation                  CFRunLoopRunSpecific + 612
18  GraphicsServices                GSEventRunModal + 164
19  UIKitCore                       -[UIApplication _run] + 888
20  UIKitCore                       UIApplicationMain + 340
21  app                             main (main.m:43)
22  (null) 0x00000001f694e960 0x0 + 8431921504

问题描述

在iOS15、iOS16系统中开启BackgroundFetch功能后,应用在后台发生崩溃。根据日志显示,所有崩溃均发生在后台,且崩溃位置已大致定位,但该如何修复?

原崩溃代码

- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    if (self.currentCompletionHandler && self.currentCompletionHandler != completionHandler) {
        self.currentCompletionHandler(UIBackgroundFetchResultNoData);
    }
    self.currentCompletionHandler = completionHandler;
    
    //执行相关操作
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if (self.currentCompletionHandler) {
            self.currentCompletionHandler(UIBackgroundFetchResultNewData);  //崩溃代码行
            self.currentCompletionHandler = nil;
        }
    });
}

崩溃原因分析

核心问题是延迟调用BackgroundFetch的completionHandler,且未遵循系统任务生命周期规则:

  • iOS15+对BackgroundFetch任务的生命周期管控更严格,系统会给应用一段有限的后台执行时间,超时或任务结束后,对应的completionHandler会被系统释放,此时调用会触发野指针访问错误(日志中的KERN_INVALID_ADDRESS)。
  • 将completionHandler保存为成员变量跨任务复用的逻辑也有风险,每个BackgroundFetch任务的handler与当前任务绑定,旧任务被回收后调用旧handler同样会触发崩溃。

修复方案

1. 避免无意义延迟,操作完成后立即调用handler

BackgroundFetch要求必须尽快完成操作并调用handler,禁止用dispatch_after做无意义延迟。异步操作的回调里直接触发handler即可。

2. 用后台任务API延长执行时间(如需)

如果后台操作确实需要更长时间,必须通过beginBackgroundTaskWithName:expirationHandler:申请额外后台时间,确保handler调用时任务未被系统回收。

3. 不要保存completionHandler为成员变量

每个BackgroundFetch任务独立处理,避免跨任务复用handler。

修正后代码示例

- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    // 申请后台任务,防止系统提前回收当前任务
    __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithName:@"BackgroundFetchTask" expirationHandler:^{
        // 超时后必须结束任务并调用handler
        [application endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
        completionHandler(UIBackgroundFetchResultNoData);
    }];
    
    // 执行实际的异步后台操作(比如网络请求、本地数据更新)
    [self executeBackgroundFetchOperation:^(BOOL hasNewData) {
        UIBackgroundFetchResult result = hasNewData ? UIBackgroundFetchResultNewData : UIBackgroundFetchResultNoData;
        completionHandler(result);
        
        // 操作完成后结束后台任务
        if (bgTask != UIBackgroundTaskInvalid) {
            [application endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        }
    }];
}

// 模拟实际后台操作的方法
- (void)executeBackgroundFetchOperation:(void(^)(BOOL hasNewData))completion {
    // 切换到全局队列执行耗时操作
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 这里替换成你的实际业务逻辑(比如网络请求、数据同步)
        [NSThread sleepForTimeInterval:2];
        
        // 回到主线程回调结果
        dispatch_async(dispatch_get_main_queue(), ^{
            completion(YES); // 根据实际业务返回是否有新数据
        });
    });
}

补充注意事项

  • 后台任务也有超时限制(一般不超过10分钟,但BackgroundFetch场景下建议控制在几十秒内),超时后系统会强制终止任务。
  • 确保所有分支(成功、失败、超时)都调用completionHandler,否则系统会降低BackgroundFetch的触发频率,甚至直接禁用该功能。

内容的提问来源于stack exchange,提问作者EverMe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 17:47:15