2015-01-16 53 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 
}