iOS 应用在 AppDelegate.applicationWillResignActive 中因 EXC_BREAKPOINT (SIGTRAP) 而崩溃

iOS app crashes with EXC_BREAKPOINT (SIGTRAP) in AppDelegate.applicationWillResignActive

我有一个应用程序有非常奇怪的崩溃,我无法重现。我在 Xcode Organizer 和 AppStore connect 中看到这些崩溃,但在崩溃工具中没有看到(我试过 Sentry 和 Bugsnag)。

据我了解崩溃日志,崩溃发生在 applicationWillResignActive

Incident Identifier: A15332F7-C7E6-4618-9FEF-7A2E6AD013FF
Hardware Model:      iPhone14,5
Process:             MyApp [1533]
Path:                /private/var/containers/Bundle/Application/408766C6-5645-4592-9D89-CB8DE5D71A76/MyApp.app/MyApp
Identifier:          com.myapp.identifier
Version:             1.2.3 (123)
AppStoreTools:       13A1030d
AppVariant:          1:iPhone14,5:15
Code Type:           ARM-64 (Native)
Role:                Non UI
Parent Process:      launchd [1]
Coalition:           com.myapp.identifier [899]

Date/Time:           2021-11-12 08:04:45.3781 +0300
Launch Time:         2021-11-12 01:20:00.0202 +0300
OS Version:          iPhone OS 15.0 (19A346)
Release Type:        User
Baseband Version:    1.00.03
Report Version:      104

Exception Type:  EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x0000000100602734
Exception Note:  EXC_CORPSE_NOTIFY
Terminating Process: exc handler [1533]
Triggered by Thread:  0


Thread 0 name:
Thread 0 Crashed:
0   MyApp                           0x0000000100602734 specialized AppDelegate.applicationWillResignActive(_:) + 168
1   MyApp                           0x00000001005ff40c AppDelegate.applicationWillTerminate(_:) + 12 (<compiler-generated>:0)
2   MyApp                           0x00000001005ff40c @objc AppDelegate.applicationWillTerminate(_:) + 56
3   UIKitCore                       0x0000000186a34ddc -[UIApplication _terminateWithStatus:] + 244 (UIApplication.m:6876)
4   UIKitCore                       0x0000000186122854 -[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:] + 128 (_UISceneLifecycleMultiplexer.m:808)
5   UIKitCore                       0x00000001863172e4 -[_UISceneLifecycleMultiplexer forceExitWithTransitionContext:scene:] + 224 (_UISceneLifecycleMultiplexer.m:482)
6   UIKitCore                       0x0000000186a31a5c -[UIApplication workspaceShouldExit:withTransitionContext:] + 212 (UIApplication.m:3792)
7   FrontBoardServices              0x0000000195150c48 __63-[FBSWorkspaceScenesClient willTerminateWithTransitionContext:]_block_invoke_2 + 80 (FBSWorkspaceScenesClient.m:331)
8   FrontBoardServices              0x000000019510b6c4 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 240 (FBSWorkspace.m:352)
9   FrontBoardServices              0x0000000195150be0 __63-[FBSWorkspaceScenesClient willTerminateWithTransitionContext:]_block_invoke + 132 (FBSWorkspaceScenesClient.m:328)
10  libdispatch.dylib               0x0000000183346950 _dispatch_client_callout + 20 (object.m:560)
11  libdispatch.dylib               0x000000018334a3e8 _dispatch_block_invoke_direct + 264 (queue.c:489)
12  FrontBoardServices              0x000000019510cfa4 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 48 (FBSSerialQueue.m:157)
13  FrontBoardServices              0x000000019510c3e4 -[FBSSerialQueue _targetQueue_performNextIfPossible] + 220 (FBSSerialQueue.m:181)
14  FrontBoardServices              0x00000001951109f4 -[FBSSerialQueue _performNextFromRunLoopSource] + 28 (FBSSerialQueue.m:194)
15  CoreFoundation                  0x00000001836f6030 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28 (CFRunLoop.c:1972)
16  CoreFoundation                  0x0000000183706cf0 __CFRunLoopDoSource0 + 208 (CFRunLoop.c:2016)
17  CoreFoundation                  0x0000000183640ff8 __CFRunLoopDoSources0 + 268 (CFRunLoop.c:2053)
18  CoreFoundation                  0x0000000183646804 __CFRunLoopRun + 820 (CFRunLoop.c:2951)
19  CoreFoundation                  0x000000018365a3c8 CFRunLoopRunSpecific + 600 (CFRunLoop.c:3268)
20  GraphicsServices                0x000000019ee6b38c GSEventRunModal + 164 (GSEvent.c:2200)
21  UIKitCore                       0x00000001860000bc -[UIApplication _run] + 1100 (UIApplication.m:3457)
22  UIKitCore                       0x0000000185d7dbe8 UIApplicationMain + 2124 (UIApplication.m:5013)
23  MyApp                           0x00000001004a5b18 main + 68 (AppDelegate.swift:19)
24  dyld                            0x000000010092da24 start + 520 (dyldMain.cpp:876)

在 applicationWillResignActive 中,我正在从本地领域获取数据并更新 UserDefaults 中的值。

class AppDelegate: UIResponder, UIApplicationDelegate {
    let provider = Provider()

    func applicationWillResignActive(_ application: UIApplication) {
        if userDefaults.bool(forKey: UserDefaults.Keys.keyWidgetEnabled) {
             provider.updateUserDefaults()
        }
    }
}

class Provider {
    let database = try! Realm()

    ...
    
    func updateUserDefaults() {
        let defaults = UserDefaults(suiteName: "com.MyApp.identifier")
        let currentDisplayDate = CalculationsHelper.getUTCSubmitDate()
        let predicateHistoryDisplayDate = NSPredicate(format: "type=%@ AND currentSubmitDate = %@", keyDBFood, currentDisplayDate.absoluteDate as NSDate)
        
        let data = self.database.objects(History.self).filter(predicateHistoryDisplayDate)
        
        mealTypesDB.allFoodTypes.forEach{ (type) in
            let key = "widget-" + type.rawValue
            let predicate = NSPredicate(format: "meal=%@", type.rawValue)
            let kcal: Int = data.filter(predicate).sum(ofProperty: "kcal")
            defaults?.set(kcal, forKey: key)
        }
        
        //set the date of the next day to update the button
        let currentSubmitDate = CalculationsHelper.getLocalSubmitDate()
        defaults?.set(currentSubmitDate, forKey: "widget-submitDate")
        defaults?.synchronize()
        if #available(iOS 14.0, *) {
            WidgetCenter.shared.reloadAllTimelines()
        }
    }
}

每次用户将应用程序发送到后台时,我都会为每个用户执行此操作,但一周以来,我只为安装了我的小部件的一小部分用户执行此操作。但是崩溃的次数几乎没有变化,所以我认为这个错误与 Realm 或 UserDefaults 无关。

据我从 AppStore connect 得知,我一直有这个错误,但只有在 iOS 15 发布后,崩溃次数才急剧增加。我不太确定如何解决这个问题,以及 iOS 15 中到底发生了什么变化,可能会导致崩溃数量急剧增加。

我找到了这个帖子 https://developer.apple.com/forums/thread/106261 并尝试重命名项目中的所有图像,以便文件名与 Assets 中的名称匹配,但这没有用。

有谁知道我能做些什么来至少找出崩溃的原因?

您是在给 applicationWillResignActive 打电话吗?看起来你是从 AppDelegate.applicationWillTerminate 调用它的。您永远不应该自己调用 UIAppDelegate 方法,这是一种反模式。虽然我不确定这会导致崩溃,但您可能想引入一个单独的方法,您可以从两者中调用。

您使用的是自定义崩溃报告器(Sentry、Bugsnag 等)这一事实可能是个问题。当您的应用程序崩溃时,Apple 的崩溃报告器可能会感到困惑,您得到的报告行将是完全错误的。

您可以在此 Apple dev forum post 上找到 Apple 工程师提供的更多详细信息。他建议仅使用 Apple 自己的崩溃报告器,因为第三方崩溃报告器与您的应用程序进程相关联,并且在您的应用程序崩溃时尝试获取它时可能会破坏堆栈跟踪,从而导致 Xcode 中的错误报告。

我联系了 Apple TSI,他们告诉我检查 applicationWillResignActiveapplicationWillTerminate 方法中的对象是否为 nil。令我惊讶的是,在调用 applicationWillTerminate 的那一刻,对象真的是零。

但是谁能解释一下这是怎么可能的?该对象在 didFinishLaunchingWithOptions 中初始化,在应用程序生命周期中我从未将其设置为 nil 。是否有可能 iOS 由于某种原因试图终止应用程序(例如内存不足)并试图从内存中一个一个地删除所有对象,并且当 applicationWillTerminate 被调用时,对象是已经从内存中删除,因此它是零?但是在什么时候允许将 运行 class?

的变量归零

更新:

我收到了 Apple 团队的回复,我觉得这很有趣。他们说 didFinishLaunchingWithOptions 将始终在其他生命周期委托之前被调用 “标准”生命周期,如 applicationWillResignActiveapplicationDidEnterBackground。但是,applicationWillTerminate 并非如此。这 终止过程可以发生在正常的生命周期流程之外,并且在 至少在理论上,没有理由它以前不会发生 didFinishLaunchingWithOptions实际被调用了

因此,如果我在 didFinishLaunchingWithOptions 中初始化的 AppDelegate 中有一个可选变量,它在 applicationWillTerminate 中仍然可以为 nil。这就是导致一些用户崩溃的原因。