【问题标题】:How to use optional chaining while searching through a dictionary in swift?如何在快速搜索字典时使用可选链接?
【发布时间】:2015-03-14 22:50:19
【问题描述】:

我想使用 if let 安全地搜索 swift Dictionary 中的值,并确保它是类型安全的,因为我对字典越来越深入。该字典包含包含 NSArray 的字典,其中包含更多字典。

第一次尝试我的代码如下所示:

  if let kkbox = ticket["KKBOX"] as? Dictionary<String, AnyObject> {
        if let kkboxDlUrlDict = kkbox["kkbox_dl_url_list"] as? Dictionary<String, AnyObject> {
            if let kkboxDlUrlArray = kkboxDlUrlDict["kkbox_dl_url"] as? NSArray {
                for dict in kkboxDlUrlArray {
                    if let name = dict["name"] as? String {
                        if name == mediaType.rawValue {
                            urlStr = dict["url"] as String
                        }
                    }
                }
            } else { return nil }
        } else { return nil }
    } else { return nil }

如何将其缩短为一两行?

我意识到如果它是 2 层,我可以链接它。这有效:

 if let kkboxDlUrlArray = ticket["KKBOX"]?["kkbox_dl_url_list"] as? NSArray {

    }

但是任何比这更长的链都不会编译。

有没有办法多次链接字典?

谢谢

【问题讨论】:

  • SwiftyJSON 可能有助于简化一些。见github.com/SwiftyJSON/SwiftyJSON
  • 您的else 子句返回nil,但您的主子句分配给urlStr?那不会编译。换句话说,如果我们知道预期回报,我们也许可以利用map() 和相关函数。
  • @MaxMacLeod SwiftJSON 很漂亮!这正是我一直在寻找的。非常感谢先生。

标签: swift dictionary optional-chaining


【解决方案1】:

你可以链接,但在每一步都要适当地向下:

if let kkboxDlUrlArray = ((((ticket["KKBOX"] as? Dictionary<String, AnyObject>)?["kkbox_dl_url_list"]) as? Dictionary<String, AnyObject>)?["kkbox_dl_url"]) as? NSArray {
    for dict in kkboxDlUrlArray {
        println(dict)
    }
}

虽然看起来不太好 - 这是一行,但不可读。

就我个人而言,在不使用任何花哨的函数式方法的情况下,我会通过一个可选绑定使链更加明确:

let kkbox = ticket["KKBOX"] as? Dictionary<String, AnyObject>
let kkboxDlUrlDict = kkbox?["kkbox_dl_url_list"] as? Dictionary<String, AnyObject>
if let kkboxDlUrlArray = kkboxDlUrlDict?["kkbox_dl_url"] as? NSArray {
    for dict in kkboxDlUrlArray {
        println(dict)
    }
}

在我看来更容易阅读,并且没有不必要的缩进

【讨论】:

  • 感谢 Antonio,这也是一个不错的解决方案。
【解决方案2】:

或者,你可以使用这个扩展,它模仿了原来存在于 NSDictionary 中但由于某种原因被砍掉的 valueForKeyPath 方法:

斯威夫特 4.1

extension Dictionary where Key: ExpressibleByStringLiteral {

func valueFor(keyPath: String) -> Any? {
    var keys = keyPath.components(separatedBy: ".")
    var val : Any = self
    while keys.count > 0 {
        if let key = keys[0] as? Key {
            keys.remove(at: 0)
            if let dic = val as? Dictionary<Key, Value> {
                if let leaf = dic[key] {
                    val = leaf
                } else {
                    return nil
                }
            } else {
                return nil
            }
        } else {
            return nil
        }
    }
    return val
}

然后您的代码将显示为:

if let array = ticket.valueFor("KKBOX.kkbox_dl_url_list.kkbox_dl_url") as? [] {
  // do something with array
}

【讨论】:

    【解决方案3】:

    好像 swift 1.2 加入了这个功能。

    “使用 if let 进行更强大的可选解包 - if let 构造现在可以一次解包多个可选项,并包括中间的布尔条件。这让您可以表达条件控制流,而无需不必要的嵌套。”

    https://developer.apple.com/swift/blog/

    【讨论】:

    • 所以这被认为是一个功能??我有 10 级深度的字典。语法越来越疯狂
    猜你喜欢
    • 2017-11-11
    • 1970-01-01
    • 1970-01-01
    • 2013-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-17
    相关资源
    最近更新 更多