I am using push notifications for an iOS chat app.

I have successfully implemented and receive push notifications and also implemented background fetch.

When I upload a new build either for TestFlight or through he store, I can correctly run through the function didReceiveRemoteNotification until the completionHandler only for several push notifications. ( about 10 or so ) in background mode.

After that the function does not run in background mode. It either get's out of sync or stops working. I know apple limits apps in background mode but not sure this is the case as this function call in my case only takes less than one second to process:

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

    let state = UIApplication.shared.applicationState
    if state == .background {
        if saveNotificationData(userInfo: userInfo) {
            completionHandler(UIBackgroundFetchResult.newData)
        } else {
            completionHandler(UIBackgroundFetchResult.noData)
        }
    } else {
        completionHandler(UIBackgroundFetchResult.noData)
    }
}

private func saveNotificationData(userInfo: [AnyHashable: Any]) -> Bool {

    let context = self.privateContext

    var result = false

    if let chatRoomId = (userInfo["chatRoomId"] as? String) {
        do {
            let fetchRequest: NSFetchRequest<Room> = Room.fetchRequest()
            fetchRequest.predicate = NSPredicate(format: "chatRoomId == %@", chatRoomId)
            let fetchedResults = try context.fetch(fetchRequest)
            if fetchedResults.count > 0 {

                let message = Message(context: context)
                message.messageRoomId = userInfo["chatRoomId"] as? String
                message.messageCreatorUserId = userInfo["user_id"] as? String
                message.messageText = userInfo["message_text"] as? String
                message.messageChatRoom = fetchedResults.first!

                do {
                    try context.save()
                    result = true
                } catch {
                    print(error)
                }
            }
        } catch {

            // error fetching list
            print("Could not fetch \(error)")
        }
    }

    return result

}

I have tried so many different ways to do this including using the main context instead of a defined background context. Putting the save function in a context.perform block, dispatching to main queue prior to returning the completionHandler.

But the result is always the same. The functions run as expected for the first few notifications and then stop working in background mode. Either getting out of sync or just being locked out. It seems the previous function execution continues when the next push is received which throws things out of order.

I am also implementing didReceive and willPresent but I have removed them completely to see if it made any difference but it did not. Really stuck here and no idea what is causing the problem.

I wonder if it is an out of sync case if when executing the new push I can cancel what is ongoing from the previous one? But that may not be the problem.

0 Answers