Connect iOS SDK crashing on call to sendMessage()

Hello!

Looking for some help here. We have a ConnectIQ app out that is frequently crashing when calling the sendMessage function from the iOS SDK (v1.3). It is terminating with the following error:
Fatal Exception: NSInvalidArgumentException. *** -[__NSDictionaryM setObject:forKeyedSubscript:]: key cannot be nil

Here is the relevant stack trace:
...
10 libc++abi.dylib 0x183b4054c std::__terminate(void (*)()) + 16
11 libc++abi.dylib 0x183b3fea8 __cxxabiv1::exception_cleanup_func(_Unwind_Reason_Code, _Unwind_Exception*) + 134
12 libobjc.A.dylib 0x183b5065c _objc_exception_destructor(void*) + 362
13 CoreFoundation 0x18489fc9c _CFArgv + 110
14 CoreFoundation 0x184944c3c -[__NSDictionaryM setObject:forKeyedSubscript:] + 940
15 ConnectIQ 0x105cec684 -[IQTaskManager getTasksForDevice:] + 268
16 ConnectIQ 0x105cec1c8 -[IQTaskManager queueTask:forceStart:] + 88
17 ConnectIQ 0x105ceac58 -[IQTaskManager sendMessage:toApp:progress:completion:] + 276
18 ConnectIQ 0x105cf1dd0 -[ConnectIQ sendMessage:toApp:progress:completion:] + 148
19 MyApp 0x104d94938 GarminConnectManager.sendMessage(Any) -> () (GarminConnectManager.swift:133)


We're having trouble reproducing the issue, which we thought might be because some `nil` values are being passed as values in dictionaries or arrays, but that does not cause a crash upon testing. We've also tried testing that the IQDevice's UUIDs are not `nil` for the IQApp we are sending the message to with no luck. We are passing only the specified NSString, NSNumber, NSNull, NSArray, or NSDictionary that the docs request. The app is written in Swift if that relevant.

Would love if anyone has any ideas or suggestions to try! Thanks!
  • I seemed to have fixed the issue by doing one, or both of the following. (All example code is in Swift 4)

    (1) Slight improvements to my JSON sanitization function to return NSNull() in the default case. Here it is, in case anyone wants it:

    func sanitize(object: Any) -> Any {

    if let date = object as? Date {
    return date.jsonFormat
    }

    if let data = object as? Data {
    return data.jsonFormat
    }

    if let data = object as? String {
    return data as NSString
    }

    if let boo = object as? Bool {
    return NSNumber(booleanLiteral: boo)
    }

    if let number = object as? Int {
    return NSNumber(value: number)
    }

    if let number = object as? Double {
    return NSNumber(value: number)
    }

    if let array = object as? [Any] {
    return array.map({ (arrayObject) -> Any in
    sanitize(object: arrayObject)
    }) as NSArray
    }

    if let object = object as? [String : Any] {
    let newDictionary = NSMutableDictionary()
    for (key, value) in object {
    let sanitizedValue = sanitize(object: value)
    newDictionary.setValue(sanitizedValue, forKey: key)
    }
    return newDictionary
    }

    return NSNull() // this fixed it
    }



    (2) Checking that the UUID for the IQDevice is not `nil` before sending the message with a simple `guard` statement:

    func sendMessage(_ message: Any, to app: IQApp) {

    guard app.device.uuid != nil else { return } // checking for non-nil UUID

    let sanitized = sanitize(object: message) // uses above sanitize function

    ConnectIQ.sharedInstance().sendMessage(sanitized, to: app, progress: { (sent, total) in

    let percentage: Double = Double(sent) / Double(total)
    let percentageInt = Int(percentage * 100.0)
    print("[Garmin] Sending message... \(percentageInt) %")

    }) { (result) in
    print("[Garmin] Message sent: \(result.description)")
    }

    }