Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice to find out if SwiftyJSON dictionary has key

I'm trying to find a way to get the value of a key in a SwiftyJSON dictionary and return a default string, if the key is not set. The following example works fine, but I'm not really satisfied. Do you know a more elegant way?

Example:

let users: JSON = [
    ["id": 1, "name": "one"],
    ["id": 2],
    ["id": 3, "name": "three"]
]
    
for (key: String, user: JSON) in users {      
    println(user.object.objectForKey("name") != nil
        ? user["name"].stringValue
        : "default")
}
like image 621
tomatentobi Avatar asked Dec 16 '14 23:12

tomatentobi


4 Answers

The latest version of SwiftyJSON has the exists() function.

NOTE: Their latest documentation does not reflect the code very well... The actual method is exists()

// Returns boolean

json["name"].exists()
like image 134
ciauri Avatar answered Sep 25 '22 22:09

ciauri


It seems, SwiftyJSON sets the error property when subscript non-existing key.

So, this should works:

for (key: String, user: JSON) in users {
    let name = user["name"];
    println(name.error == nil ? name.stringValue : "default")
}

For example: w/ Version 6.1.1 (6A2006), SwiftyJSON github current master:

let users: JSON = [
    ["id": 1, "name": "one"],
    ["id": 2],
    ["id": 3, "name": NSNull()],
    ["id": 4, "name": "four"],
]

for (key: String, user: JSON) in users {
    let name = user["name"];
    name.isEmpty
    println(name.error == nil ? name.stringValue : "default")
}

prints:

one
default

four
like image 44
rintaro Avatar answered Sep 23 '22 22:09

rintaro


If you need to check if a SwiftyJSON dictionary has a key, you can compare it with JSON.null as follows:

user["name"] == JSON.null // true if the key does not exist

Using that method, your code could look like this:

let users: JSON = [
    ["id": 1, "name": "one"],
    ["id": 2],
    ["id": 3, "name": "three"]
]

for (key, user) in users {
    print(user["name"] != JSON.null ? user["name"].stringValue : "default")
}

If you just want to provide a default value, then you can use the Nil Coalescing Operator in Swift (??) like this:

let users: JSON = [
    ["id": 1, "name": "one"],
    ["id": 2],
    ["id": 3, "name": "three"]
]

for (key, user) in users {
    print(user["name"].string ?? "default")
}

SwiftJSON provides the string method, which returns an optional value (String?), contrary to stringValue which always returns a String.

like image 27
Eneko Alonso Avatar answered Sep 25 '22 22:09

Eneko Alonso


Objects of type JSON have a calculated property called null. This returns NSNull if the element requested does not exist, nil if it does. You can therefore test for the existence of a specific object by extracting it from its parent JSON and testing to see if the null property exists. I personally handle it like this:

let object = json["key"]
if object.null == nil {
    // Do something with 'object'
} else {
    // Key does not exist - handle the error
}

In your specific case, you could use this:

for (key: String, user: JSON) in users {
    let name = user.object.objectForKey("name")
    println(name.null == nil ? name.stringValue : "default")
}

...but since we know we're looking for a string we can cut that down even further. All you actually need to do is drop the 'Value' part of stringValue, since string will return nil if it cannot generate a string from its content. Also, check out the nil coalescence operator ??. It's designed to provide a default for optional variables, so try this:

for (key: String, user: JSON) in users {
    println(user["name"].string ?? "default")
}

Nice and compact!

like image 37
Ash Avatar answered Sep 24 '22 22:09

Ash