2015-01-16 28 views
4

我想安全地搜索一个swift字典中的值,使用if let,并确保它是类型安全的,因为我越来越深入到字典中。该字典包含包含更多字典的NSArray的字典。在swift中搜索字典时如何使用可选链接?

在第一次尝试我的代码看起来是这样的:

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线?

我意识到如果它是2层,我可以链接它。这个工程:

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

    } 

但是任何更长的链,不会编译。

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

谢谢

+2

SwiftyJSON可能有助于简化。请参阅https://github.com/SwiftyJSON/SwiftyJSON。 –

+0

您的'else'子句返回'nil',但您的主子句分配给'urlStr'?这不会编译。换句话说,如果我们知道预期的回报,我们可能会利用'map()'和相关函数。 – GoZoner

+1

@MaxMacLeod SwiftJSON很漂亮!这正是我所期待的。非常感谢先生。 –

回答

0

似乎像swift 1.2已添加此功能。

“如果let让更强大的可选解包功能 - if let构造现在可以立即拆开多个可选项,并且包含中间布尔条件,这可以让您表达条件控制流而不会产生不必要的嵌套。

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

+0

所以这被认为是一个功能?我有10个级别的字典。语法越来越疯狂 –

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

在我看来更容易阅读,并没有不必要的压痕

+0

谢谢安东尼奥,这也是一个不错的解决方案。 –

1

或者,你可以使用这个扩展,它模仿的是用于NSDictionary的存在,但得到砍掉无论什么原因,原来valueForKeyPath方法:

extension Dictionary where Key: StringLiteralConvertible { 
    func valueFor(keyPath: String) -> Any? { 
     var keys = keyPath.componentsSeparatedByString(".") 
     var val : Any = self 
     while keys.count > 0 { 
      if let key = keys[0] as? Key { 
       keys.removeAtIndex(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 
}