简体   繁体   中英

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)") } }

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM