completionHandler of the 2 methods performFetchWitchCompletionHandler AND didReceiveRemoteNotification interfere each other?
Asked Answered
L

2

26

I have a iOS (swift) Application available AppStore since November 2017. I added Firebase Analytics and Crashlytics to proactively see issues which didn't occur during development and testing.

I'm currently struggling with the following Stacktrace, which I get several times in my Firebase Crashlytics Dashboard:

Stacktrace from Firebase

Fatal Exception: NSInternalInconsistencyException this request has been neutered - you can't call -sendResponse: twice nor after encoding it

Fatal Exception: NSInternalInconsistencyException
0  CoreFoundation                 0x1ac20bef8 __exceptionPreprocess
1  libobjc.A.dylib                0x1ab3d9a40 objc_exception_throw
2  CoreFoundation                 0x1ac12006c +[_CFXNotificationTokenRegistration keyCallbacks]
3  Foundation                     0x1acc0c3e0 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:]
4  BaseBoard                      0x1aea6cd68 __40-[BSAction sendResponse:withCompletion:]_block_invoke
5  libdispatch.dylib              0x1abc44484 _dispatch_client_callout
6  libdispatch.dylib              0x1abc24754 _dispatch_lane_barrier_sync_invoke_and_complete
7  BaseBoard                      0x1aea20c60 -[BSAction sendResponse:withCompletion:]
8  UIKitCore                      0x1d8c20698 -[UIHandleRemoteNotificationAction sendResponse:]
9  UIKitCore                      0x1d9054d3c __91-[UIApplication _handleNonLaunchSpecificActions:forScene:withTransitionContext:completion:]_block_invoke_3.2891
10 libdispatch.dylib              0x1abc436c8 _dispatch_call_block_and_release
11 libdispatch.dylib              0x1abc44484 _dispatch_client_callout
12 libdispatch.dylib              0x1abc23b44 _dispatch_main_queue_callback_4CF$VARIANT$armv81
13 CoreFoundation                 0x1ac19a1bc __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
14 CoreFoundation                 0x1ac195084 __CFRunLoopRun
15 CoreFoundation                 0x1ac1945b8 CFRunLoopRunSpecific
16 GraphicsServices               0x1ae408584 GSEventRunModal
17 UIKitCore                      0x1d903cbc8 UIApplicationMain
18 <APP-NAME>                     0x10251bc84 main (AppDelegate.swift:18)
19 libdyld.dylib                  0x1abc54b94 start

The weird thing is, that during development and testing, this specific error does not occur at all.

I did a lot of research the last days regarding this topic. I found several SO posts, where this issue has been solved.

iOS8 background fetch issue

iOS 8 NSInternalInconsistencyException

Unable to understand where MyApp is crashing

Basically the crash occurs when you call the completionHandler twice. But in different posts they are referring to 2 different methods, but both have the same completionHandler:

performFetchWitchCompletionHandler

func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
  // code here
  completionHandler(.newData)
}

didReceiveRemoteNotification

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
  // code here
  completionHandler(.newData)
}

I cannot find a position where I call the completionHandler of both methods twice. My question would be, if it is possible to implement both methods in the AppDelegate without getting the mentioned error above. Or does the parallel implementation of the two methods performFetchWitchCompletionHandler and didReceiveRemoteNotification interfere each other?

Luba answered 18/10, 2018 at 17:12 Comment(6)
could you share the code in compilation handlerBlower
the code in the completion handler doesn't matter in our case, because I have it only one time per function. my question was rather in the direction if these two methods are interfering each other, or more explicit - are the completion handlers of the two methods are interfering each other, because I get still the mentioned errorLuba
your stack trace matched mine and the error and your commentary helped me narrow my search using UIHandleRemoteNotificationAction. I looked at AppDelegate's func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) and found that completionHandler was getting called twice. I'm sure that was the cause of my crashes when user tapped a push notification (message) that triggered a launch of the app.Jocelyn
@Jocelyn I have the exact same issue on my app. Were you able to fix the issue? If so, how?Reduplicate
@Reduplicate - In my case I had a for loop, which was performed multiple times where I called my completion handler. Once I called the completion handler in the loop, I exited the loop manually. BUT in my case I had another listener, which was called additionally, if my app was close to be terminated.Luba
I am having the same issue, is this something that Firebase can solve?Vale
A
1

I'm not sure how to explain it, but it sounds like a "race condition", the methods are being invoked "closely together". I would try wrapping the completion in a

DispatchQueue.main.asyncAfter with interval of .now()

Unless you'd like to mock and try manually invoking the method twice.

Araucanian answered 29/11, 2021 at 19:7 Comment(0)
L
1

It seems like decode happened twice at the same time, try use lock like codes below:

 private let mutex = DispatchSemaphore(value: 1)
    
    func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        // code here
        mutex.wait()
        completionHandler(.newData)
        mutex.signal()
    }
    
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        // code here
        mutex.wait()
        completionHandler(.newData)
        mutex.signal()
    }
Lunular answered 28/6, 2023 at 2:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.