Search code examples
iosswiftfoundation

Catching NSJSONSerialization errors in Swift


I'm trying to understand why I'm unable to catch the errors thrown by NSJSONSerialization.

I expect the NSInvalidArgumentException exception to be raised and caught, but instead the app crashes.

This is occurring in both Swift 3 and Swift 2.3 using Xcode 8.

Swift 3:

    do {
        _ = try JSONSerialization.data(withJSONObject: ["bad input" : NSDate()])
    }
    catch {
        print("this does not print")
    }

Swift 2.3:

    do {
        _ = try NSJSONSerialization.dataWithJSONObject(["bad input" : NSDate()], options: NSJSONWritingOptions())
    }
    catch {
        print("this does not print")
    }

This code is put in applicationDidFinishLaunching inside a blank Xcode project. Tested on both simulator and device.

Full exception:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (__NSDate)'

Any ideas why the catch block is not catching this particular error?


Solution

  • From the documentation for JSONSerialization data(withJSONObject:options:):

    If obj will not produce valid JSON, an exception is thrown. This exception is thrown prior to parsing and represents a programming error, not an internal error. You should check whether the input will produce valid JSON before calling this method by using isValidJSONObject(_:).

    What this means is that you can't catch the exception caused by invalid data. Only "internal errors" (whatever that actually means) can be caught in the catch block.

    To avoid a possible NSInvalidArgumentException you need to use isValidJSONObject.

    Your code then becomes:

    do {
        let obj = ["bad input" : NSDate()]
        if JSONSerialization.isValidJSONObject(obj) {
            _ = try JSONSerialization.data(withJSONObject: obj)
        } else {
            // not valid - do something appropriate
        }
    }
    catch {
        print("Some vague internal error: \(error)")
    }