如何最佳实践地判断SwiftyJSON字典是否包含某个键名

23

我正在尝试找到一种方法,以获取SwiftyJSON字典中键的值,并在未设置键时返回默认字符串。以下示例可以正常运行,但并不理想。您知道更加优雅的方式吗?

示例:

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

你有没有找到解决方案?谢谢! - Hannes
@Hannes:不好意思,不行。 - tomatentobi
我认为现在有更好的JSON库可用,在大多数情况下,ObjectMapper效果更好,因为它会创建对象,而不是必须浏览各种字符串类型的可选字典项。 - Lucas van Dongen
6个回答

28

SwiftyJSON的最新版本有exists()函数。

注意:它们最新的文档没有很好地反映出代码... 实际上方法应该是exists()

// Returns boolean

json["name"].exists()

至少在SwiftyJSON的2.3.3版本和3版本中,该方法仍为isExists() - Rool Paap
SwiftyJSON(3.1.3)使用.exists()语法。 - Otávio
对我没有作用,即使值为空也打印 true。 - Evgeniy Kleban

9

看起来,当 subscript 访问不存在的键时,SwiftyJSON 会设置 error 属性。

所以,这应该可以正常工作:

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

例如:使用版本6.1.1(6A2006),SwiftyJSON github当前主分支:
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")
}

打印:

one
default

four

1
我也尝试过这种方式,但是在 let name = user["name"]; 后直接崩溃了。 - tomatentobi
至少在我的环境中可以工作,如答案所述。请提供更多信息,什么错误? - rintaro
你的版本(http://imgur.com/ZDiyRds)在第二个用户之前是有效的。然后它找不到getter(http://imgur.com/GgjiEUA)。你使用了不同的主程序吗?https://github.com/SwiftyJSON/SwiftyJSON/blob/master/Source/SwiftyJSON.swift - tomatentobi

7

如果您需要检查 SwiftyJSON 字典是否具有键,您可以像下面这样将其与 JSON.null 进行比较:

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

使用这种方法,你的代码可以像这样:

使用这种方法,你的代码可以像这样:

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

如果你只想提供一个默认值,那么你可以在Swift中使用Nil Coalescing Operator??)来实现:

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

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

SwiftJSON提供了string方法,该方法返回一个可选值(String?),与stringValue相反,后者总是返回一个String


1

类型为JSON的对象有一个名为null的计算属性。如果请求的元素不存在,则返回NSNull,否则返回nil。因此,您可以通过从其父JSON中提取它并测试null属性是否存在来测试特定对象的存在性。我个人是这样处理的:

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

在您的特定情况下,您可以使用以下内容:
for (key: String, user: JSON) in users {
    let name = user.object.objectForKey("name")
    println(name.null == nil ? name.stringValue : "default")
}

...但是既然我们知道我们正在寻找一个字符串,我们甚至可以进一步缩小范围。实际上,您只需要删除 stringValue 的 'Value' 部分,因为如果无法从其内容生成字符串,则 string 将返回 nil。此外,请查看空值合并运算符 ??。它旨在为可选变量提供默认值,因此请尝试以下操作:

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

不错,很紧凑!

哎呀,我刚意识到我的回答和你最后写的部分几乎一样了。好吧,为了更方便地访问,我想我会留下这个答案。 - Mazyod

0
据我所知,这个是有效的:
let users: JSON = [
    ["id": 1, "name": "one"],
    ["id": 2],
    ["id": 3, "name": "three"]
]

for jsonDict in users.arrayValue {      
    println(jsonDict["name"].string ?? "default")
}

简单来说,您想将 JSON 对象转换为您期望获得的类型。如果您希望该类型始终成功(不是可选的),请使用 xxxValue。因此,我们使用 arrayValue 转换根对象。

arrayValue 返回 [JSON],我们在循环中遍历它。我们不需要将 jsonDict: JSON 强制转换为对象,因为 SwiftyJSON 足够聪明,可以从下标运算符中假定它是一个字典。

最后,尝试从字典中获取键,然后检查是否可以使用 .string 将键作为字符串检索出来,这是一个可选项。使用空合并运算符分配默认值。

请参阅 SwiftJSON 文档以了解 stringstringValue


-1

注意:此答案不再有效

看起来这是使用if let语法的完美场景。因为访问下标会返回一个可选项,所以将其绑定到if let块中的变量中。这将告诉您键是否在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
}

不,这是无效的:http://i.imgur.com/ST0MgLX.png。将其转换为JSON格式也会崩溃:http://i.imgur.com/wpwlI6H.png。 - tomatentobi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接