2

I have an application which crashes on launch. I have identified where the problem originates, but I can't seem to figure out how to resolve it. Let me first explain what I do:

I have a LocationManager that checks if a user enters a certain region (using startRegionMonitoring). If so, a local notification is scheduled to fire in 5 minutes. If however, the person leaves again within those 5 minutes, the local notification is canceled. I do this because a user can just pass by the building without actually entering it. It also cancels any pending notifications (within those 5 minutes) when the app is opened by the user himself.

When this scenario occurs, the app crashes upon launch. The crash report indicates this:

Exception Type:  EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x000000010098b38c
Triggered by Thread:  0

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   GetReminded                     0x000000010098b38c closure #1 in closure #1 in AppDelegate.applicationWillEnterForeground(_:) + 3388300 (AppDelegate.swift:1300)
1   GetReminded                     0x00000001006be738 thunk for @escaping @callee_guaranteed () -> () + 452408 (<compiler-generated>:0)
2   libdispatch.dylib               0x00000001b6448a38 0x1b63e9000 + 391736
3   libdispatch.dylib               0x00000001b64497d4 0x1b63e9000 + 395220
4   libdispatch.dylib               0x00000001b63f7004 0x1b63e9000 + 57348
5   CoreFoundation                  0x00000001b699ac1c 0x1b68f1000 + 695324
6   CoreFoundation                  0x00000001b6995b54 0x1b68f1000 + 674644
7   CoreFoundation                  0x00000001b69950b0 0x1b68f1000 + 671920
8   GraphicsServices                0x00000001b8b9579c 0x1b8b8b000 + 42908
9   UIKitCore                       0x00000001e31c4978 0x1e2908000 + 9161080
10  GetReminded                     0x0000000100681f4c main + 204620 (ExerciseStatistics.swift:219)
11  libdyld.dylib                   0x00000001b645a8e0 0x1b6459000 + 6368

At first, I wasn't performing the cancel action on the main thread - which is what I thought caused the crash. So I used Dispatch Queue and thought the issue would be resolved, but it's still there. My code for willEnterForeground:

UNUserNotificationCenter.current().getDeliveredNotifications { (notifications: [UNNotification]) in

    DispatchQueue.main.async {
        for notification in notifications {
            if(notification.request.content.userInfo["notificationType"] as! String == "exitReminder" || notification.request.content.userInfo["notificationType"] as! String == "enterReminder") {
                let notificationID = notification.request.identifier
                UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [notificationID])
                UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [notificationID])

            }
        }
    }

}

I'm not really sure how this can be resolved. It might be important to know that this reminder is sent from the background, so when the app is not in the foreground. I have location services on in the background, everything works when I stay at the location, but it goes wrong when I exit again within those 5 mins and thus the notification needs to be canceled.

Any ideas?

PennyWise
  • 595
  • 2
  • 12
  • 37
  • No worries. Thankful you are looking into my question. Any other ideas as to what might cause this? – PennyWise Jul 14 '19 at 11:03
  • Not any idaes at this point but It can be so helpful if you share your project to look deeply on it if you want – Arash Etemad Jul 14 '19 at 11:06
  • You should replace that `as! String` with an appropriate conditional unwrap – Paulw11 Jul 14 '19 at 12:22
  • Dug into it and found this too. I am now building a new release with a safe unwrap (if let) to see how that goes. Would that be the issue, according to my code and the crash report? – PennyWise Jul 14 '19 at 12:24

1 Answers1

1

notification.request.content.userInfo["notificationType"] as! String will crash if the notificationType key returns nil (or something other than a string). You shouldn't use a force downcast without good reason.

Use defensive coding:

for notification in notifications {
        if let notificationType = notification.request.content.userInfo["notificationType"] as? String { 
             if notificationType == "exitReminder" || notificationType == "enterReminder" {
                let notificationID = notification.request.identifier
                UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [notificationID])
                UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [notificationID])

        }
    }
}
Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • Looking into it as we speak. Should indeed be the reason behind it when I think about it. Force downcast is never a good idea unless we are sure it can't return nil. – PennyWise Jul 14 '19 at 12:35