Erik Villegas Erik Villegas - 1 month ago 7
Swift Question

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?

Answer

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)")
}