Reputation: 3157
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?
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")
}
Upvotes: 23
Views: 18891
Reputation: 513
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()
Upvotes: 28
Reputation: 19682
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
.
Upvotes: 7
Reputation: 6831
Note: This answer is no longer valid
Seems like the perfect use of if let
syntax. Because accessing the subscript will return an optional, bind it to a variable in an if let
block. This will tell you wether or not the key was in the JSON
.
if let name = user["name"] { // returns optional
// user["name"] was non-nil, is now stored in ``name""
// do something with ``name""
}
else {
// user did not have key "name"
// here would be the place to return "default"
// or do any other error correction if the key did not exist
}
Upvotes: -1
Reputation: 22559
As far as I can tell, this works:
let users: JSON = [
["id": 1, "name": "one"],
["id": 2],
["id": 3, "name": "three"]
]
for jsonDict in users.arrayValue {
println(jsonDict["name"].string ?? "default")
}
To explain, you want to cast the JSON
object to the types you expect to get. If you want the type to always succeed (not optional), use xxxValue
. Hence, we cast the root object using arrayValue
.
arrayValue
returns [JSON]
, which we traverse in the loop. We don't need to case the jsonDict: JSON
to object, as SwiftyJSON is smart enough to assume it is a dict from the subscript operators.
Finally, trying to fetch a key from the dict, then checking if the key can be retrieved as a string using .string
, which is an optional. Use null coalescing to assign a default value.
Please see the SwiftJSON doc for string
and stringValue
Upvotes: 0
Reputation: 9351
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!
Upvotes: 1
Reputation: 51911
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
Upvotes: 9