Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread Handling on AppDelegate.Swift

My app was recently rejected by Apple for the following:

Exception Type:  EXC_CRASH (SIGKILL)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note:  EXC_CORPSE_NOTIFY
Termination Reason: Namespace SPRINGBOARD, Code 0x8badf00d
Termination Description: SPRINGBOARD, scene-create watchdog transgression: ********* exhausted real (wall clock) time allowance of 17.77 seconds | ProcessVisibility: Foreground | ProcessState: Running | WatchdogEvent: scene-create | WatchdogVisibility: Foreground | WatchdogCPUStatistics: ( | "Elapsed total CPU time (seconds): 37.550 (user 37.550, system 0.000), 63% CPU", | "Elapsed application CPU time (seconds): 1.015, 2% CPU" | )
Triggered by Thread:  0

Below is my code, being AppDelegate:

  1. Do I have any code running in the main thread that could have led to the rejection? I understand the rejection relates to error handling.

  2. If so, how would I move the relevant code to the background thread?

    @UIApplicationMain    class AppDelegate: UIResponder, UIApplicationDelegate {
    
        var window: UIWindow?
    
    
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
            let font = UIFont.systemFont(ofSize: 14)
            let normalAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font : font, NSAttributedString.Key.foregroundColor: UIColor.white]
            UITabBarItem.appearance().setTitleTextAttributes(normalAttributes, for: .normal)
            let selectedAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font : font, NSAttributedString.Key.foregroundColor: UIColor.appYellow]
            UITabBarItem.appearance().setTitleTextAttributes(selectedAttributes, for: .selected)
            UITabBar.appearance().unselectedItemTintColor = UIColor.white
    
            GADMobileAds.configure(withApplicationID: "xxxxxx")
    
            TWTRTwitter.sharedInstance().start(withConsumerKey: "xxxxxxxxxxxxxxx", consumerSecret: "xxxxxxxxxxxxxxxxxxx")
    
            FirebaseApp.configure()
    
            let defaults: [String: Any?] = ["bet_interstitial_frequency":       PlaceWagerViewController.DEFAULT_INTERSTITIAL_FREQUENCY,
                                            "event_interstitial_frequency": PlaceWagerViewController.DEFAULT_INTERSTITIAL_FREQUENCY,
                                            "rewarded_video_text": "View Ad",
                                            "scorecard_display_variant": "no_button",
                                            "unlock_icon_2": "coin"]
            RemoteConfig.remoteConfig().setDefaults(defaults as? [String: NSObject])
            RemoteConfig.remoteConfig().fetch(completionHandler: { (status, error) in
                if error == nil {
                    RemoteConfig.remoteConfig().activateFetched()
                }
            })
    
            Messaging.messaging().delegate = self
    
            self.window = UIWindow(frame: UIScreen.main.bounds)
    
            if(Auth.auth().currentUser) == nil {
                openLanding()
            }else {
                openHome()
            }
            return true
        }
    
        func openLanding() {
            let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
            let initialViewControlleripad = storyboard.instantiateViewController(withIdentifier: "LandingViewController")
            self.window?.rootViewController = initialViewControlleripad
            self.window?.makeKeyAndVisible()
        }
    
        func openHome() {
            let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
            let initialViewControlleripad = storyboard.instantiateViewController(withIdentifier: "HomeTabBarController") as! UITabBarController
            self.window?.rootViewController = initialViewControlleripad
            self.window?.makeKeyAndVisible()
            let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
            UNUserNotificationCenter.current().requestAuthorization(
                options: authOptions,
                completionHandler: {_, _ in })
            UIApplication.shared.registerForRemoteNotifications()
        }
    
        func handleNotification(userInfo: [AnyHashable : Any]) {
            let vc = self.window!.rootViewController!.topMostViewController()
    
            guard let pushType = userInfo["push_type"] as? String else {
                return
            }
            switch pushType {
            case "free_chips", "picks_sold":
                CashierViewController.openCashier(sender: vc)
                break
            case "bet_result":
                let wagerKey = userInfo["wager_id"] as? String ?? ""
                WagerViewController.openWager(sender: vc, wagerKey: wagerKey)
                break
            case "user_profile":
                let userId = userInfo["profile_id"] as? String ?? ""
                ProfileViewController.openPorfile(vc: vc, userId: userId)
                break
            default:
                break
            }
        }
    
    
        func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
            let sourceApplication = options[UIApplication.OpenURLOptionsKey.sourceApplication] as! String?
            if FUIAuth.defaultAuthUI()?.handleOpen(url, sourceApplication: sourceApplication) ?? false {
                return true
            }
            return false
        }
    
    
        func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    
    
            print(userInfo)
            handleNotification(userInfo: userInfo)
            completionHandler(UIBackgroundFetchResult.newData)
        }
    
    
        func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
            print("Unable to register for remote notifications: \(error.localizedDescription)")
        }
        func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
            print("APNs token retrieved: \(deviceToken)")
    
        }
    
        func handleDynamicLink(_ dynamicLink: DynamicLink) {
            guard let url = dynamicLink.url else {
                return
            }
    
    
            let splitLink = url.absoluteString.replacingOccurrences(of: "https://betshark.app/l/", with: "").split(separator: "/")
    
            if Auth.auth().currentUser != nil {
                let vc = self.window!.rootViewController!.topMostViewController()
                if splitLink[0] == "bet" {
                    WagerViewController.openWager(sender: vc, wagerKey: String(splitLink[1]))
                }
            }
        }
    
        func application(_ application: UIApplication, continue userActivity:
            NSUserActivity, restorationHandler: @escaping
            ([UIUserActivityRestoring]?) -> Void) -> Bool {
            if let incomingURL = userActivity.webpageURL {
                let handledLink =
                    DynamicLinks.dynamicLinks().handleUniversalLink(incomingURL) {
                        (dynamicLink, error) in
                        guard error == nil else {
                            print("dynmaicLink error \(error?.localizedDescription)")
                            return
                        }
    
                        if let dynamicLink = dynamicLink {
                            self.handleDynamicLink(dynamicLink)
                        }
                }
                if handledLink {
                    return true
                }else {
                    return false
                }
            }
            return false
    
        }
    }
    
    
    extension AppDelegate : MessagingDelegate {
        func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
            print("Firebase registration token: \(fcmToken)")
    
            let dataDict:[String: String] = ["token": fcmToken]
            NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
    
        }
    
        func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
            print("Received data message: \(remoteMessage.appData)")
        }
    }
    
like image 391
tccpg288 Avatar asked Aug 05 '26 06:08

tccpg288


1 Answers

Understanding and Analyzing Application Crash Reports tells us:

The exception code 0x8badf00d indicates that an application has been terminated by iOS because a watchdog timeout occurred. The application took too long to launch, terminate, or respond to system events. One common cause of this is doing synchronous networking on the main thread. Whatever operation is on Thread 0 needs to be moved to a background thread, or processed differently, so that it does not block the main thread.

The “watchdog” reference (and the code, 0x8badf00d; “ate bad food” lol) is telling you that you have something blocking the main thread (for 17.7 seconds in this example).

You need to identify what in this process (or elsewhere in your startup of the app) can possibly block for that long. You can do this by identifying which of the above are synchronous tasks. Or you can test this empirically with “time profiler” in Instruments (and you might want to try with network link conditioner to simulate really bad network conditions).

But I agree that that this Firebase issue you identified is a likely candidate.

like image 146
2 revsRob Avatar answered Aug 07 '26 18:08

2 revsRob



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!