1

If I send a remote push notification, everything works great in background / foreground. But if I kill my app and want to handle the push notification, the app starts and crashes after a few ms.

Here is my didFinishLaunchingWithOptions function:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        UNUserNotificationCenter.current().requestAuthorization(options:
            [[.alert, .sound, .badge]],
            completionHandler: { (granted, error) in
            // Handle Error
        })
        application.registerForRemoteNotifications()

        if let options: NSDictionary = launchOptions as NSDictionary? {
            let remoteNotification =
                options[UIApplicationLaunchOptionsKey.remoteNotification]

            if let notification = remoteNotification {
                self.application(application, didReceiveRemoteNotification:
                    notification as! [AnyHashable : Any],
                                 fetchCompletionHandler:  { (result) in
                })

            }
        }

        return true
}

And my didReceiveRemoteNotification function

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

        let tabBar: UITabBarController = self.window?.rootViewController as! UITabBarController
        let navController: UINavigationController = tabBar.viewControllers![1] as! UINavigationController
        let viewController = navController.viewControllers[0] as! CompanyProfileTableViewController
        //let viewController = tabBar.viewControllers![1] as! CompanyProfileTableViewController

        let notification: CKNotification = CKNotification(fromRemoteNotificationDictionary:
                userInfo as! [String : NSObject])

        print("\(notification)")

        if (notification.subscriptionID == "company-changed") {
            let queryNotification =
                notification as! CKQueryNotification
            print("\(queryNotification)")

            let recordID = queryNotification.recordID

            viewController.fetchRecord(recordID!)
        }

    }

I´m dealing with this problem for more than enough hours but can´t find a proper solution. I also checked

Handling Push Notifications when App is NOT running

If I relunch the app, changes caused by the rPN to the Labels were made. As I have to kill the app I'm not able to debug the code in Xcode while a rPN was sent to the killed app.

Here is the function to fetch records and update the labels

//Fetch records from DB
func fetchRecord(_ recordID: CKRecordID) -> Void {
    let privateDatabase = CKContainer.default().privateCloudDatabase
    var recordIDArray: [CKRecordID] = []
    recordIDArray.append(recordID)

    let fetchRecordsWithID = CKFetchRecordsOperation(recordIDs: recordIDArray)
    fetchRecordsWithID.fetchRecordsCompletionBlock = { (records, error) in
        if error != nil {
            print("Error")
        } else {
            DispatchQueue.main.async() {
                self.currentRecord = records?[recordID]

                let data = NSKeyedArchiver.archivedData(withRootObject: self.currentRecord ?? "none")
                UserDefaults.standard.set(data, forKey: "companyRecord")
                UserDefaults.standard.synchronize()

                if let retrivedData = UserDefaults.standard.object(forKey: "companyRecord") {
                    let companyRecord = NSKeyedUnarchiver.unarchiveObject(with: retrivedData as! Data) as! CKRecord
                    self.companyNameLabel.text = companyRecord["companyName"] as? String
                    self.companyStreetLabel.text = companyRecord["companyStreet"] as? String
                    self.companyZipCodeLabel.text = companyRecord["companyZipCode"] as? String
                }

            }
        }
    }
    privateDatabase.add(fetchRecordsWithID)        
}

Trace stack:

Trace Stack

I guess the problem is in the fetch record function.

Error:

; partial apply forwarder for Swift.(_fatalErrorMessage (Swift.StaticString, Swift.StaticString, Swift.StaticString, Swift.UInt, flags : Swift.UInt32) -> Swift.Never).(closure #2)
    0x1003d11e4 <+96>:  nop    
    0x1003d11e8 <+100>: mov    x0, x25
    0x1003d11ec <+104>: mov    x1, x24
    0x1003d11f0 <+108>: mov    x2, x23
    0x1003d11f4 <+112>: mov    x4, x8
    0x1003d11f8 <+116>: bl     0x1002c4b80               ; function signature specialization <preserving fragile attribute, Arg[1] = [Closure Propagated : reabstraction thunk helper from @callee_owned (@unowned Swift.UnsafeBufferPointer<Swift.UInt8>) -> () to @callee_owned (@unowned Swift.UnsafeBufferPointer<Swift.UInt8>) -> (@out ()), Argument Types : [@callee_owned (@unowned Swift.UnsafeBufferPointer<Swift.UInt8>) -> ()]> of generic specialization <preserving fragile attribute, ()> of Swift.StaticString.withUTF8Buffer <A> ((Swift.UnsafeBufferPointer<Swift.UInt8>) -> A) -> A
->  0x1003d11fc <+120>: brk    #0x1
Community
  • 1
  • 1
Luca
  • 221
  • 2
  • 11
  • Could you tell us what's your stack trace when app crashes? – carmine Feb 26 '17 at 11:26
  • @carmine What do you mean by stack trace? – Luca Feb 26 '17 at 11:27
  • http://stackoverflow.com/a/26341275/1622430 and following.. – carmine Feb 26 '17 at 11:28
  • @carmine updated my post with the trace stack (image) and the function which caused the error. – Luca Feb 26 '17 at 11:41
  • did you try to execute step by step with debugger? What is the line where the app crashes? What is the error you see in the debugger view? Some little things that can help you (and us) to solve your bug ;) – carmine Feb 26 '17 at 11:57
  • @carmine It crashes in fetchRecord function when setting the first label to the new value. Maybe they are not initialized when performing the rPN. I'm using IBOutlets for the labels. – Luca Feb 26 '17 at 12:10
  • OK I may have a solution for this. The labels aren´t initialized, so I will put the part where I set the labels to UserDefault object in viewDidAppear. UserDefaults will be updated through the rPN. – Luca Feb 26 '17 at 12:31
  • 1
    @carmine Thank your very much for your help you put me in the right direction with your questions ;). I posted the solution as an answer. – Luca Feb 26 '17 at 12:45
  • It's a pleasure ;) – carmine Feb 26 '17 at 19:17

1 Answers1

0

I finally found the solution. The problem was my fetchRecord function. The labels were not initialized when performing the rPN with a "killed" app.

So there are two ways to solve this problem:

1st:

Modify the didReceiveRemoteNotification method:

if (notification.subscriptionID == "company-changed") {
            let queryNotification =
                notification as! CKQueryNotification
            print("\(queryNotification)")

            let recordID = queryNotification.recordID
            tabBar.selectedIndex = 1
            viewController.fetchRecord(recordID!)
}

I add this ->

tabBar.selectedIndex = 1

This will show up the viewController and labels are initialized fine.

The other solution is to put the part were I set the labels with the new values into viewWillAppear or viewDidLoad.

Luca
  • 221
  • 2
  • 11