Search code examples
jsonswiftbinary-operators

Why value returned from JSON is not comparable to NSNull?


I am returning String values from API via Swift 4 JSON Codable method.

I know few values are "null" or nil, so to avoid crashes I am trying to implement code. Here is the code giving the subject error (on NSNull comparison):

if Cur[indexPath.row].cap == nil || Cur[indexPath.row].cap == NSNull {
    print("Could not find the value")
    CapVal = "N/A"
} else {
    CapVal = Cur[indexPath.row].cap!
}

The error:

Binary operator '==' cannot be applied to operands of type 'String?' and 'NSNull.Type

I tried to cast it as String too: Cur[indexPath.row].cap as? String still got the same error.


Solution

  • If you are using JSONDecoder, both missing values and values that are explicitly designated as null will be returned as nil:

    Consider this JSON:

    {"foo": "a", "bar": null}
    

    And this struct:

    struct Result: Decodable {
        var foo: String
        var bar: String?
        var baz: String?
    }
    

    If you use JSONDecoder, you can just do:

    guard let result = try? JSONDecoder().decode(Result.self, from: data) else { ... }
    
    let bar = result.bar ?? "N/A"
    

    I know you were asking about Codable in Swift 4, but just for your reference, if you were using JSONSerialization, though, you could theoretically test for null, because JSONSerialization does return null values as NSNull:

    guard let json = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any] else { ... }
    
    let bar = json["bar"]
    
    if bar == nil || bar is NSNull {
        // bar was either not found or `null`
    } else {
        // bar was found and was not `null` 
    }
    

    Personally, though, I'd just optionally cast to string and use nil coalescing operator if the cast failed, e.g.

    let bar = (json["bar"] as? String) ?? "N/A"
    

    But, this is all moot with Swift 4's JSONDecoder.