我有一个如下图所示设置的plist:
我想将其加载到变量中,然后循环遍历每个项目。这是我到目前为止的代码,但无济于事我看到了错误" Type' AnyObject'不符合协议' SequenceType'"。
func startTournament(sender: UIBarButtonItem) {
var map: NSDictionary?
if let path = NSBundle.mainBundle().pathForResource("knockout_single_8", ofType: "plist") {
map = NSDictionary(contentsOfFile: path)
}
var matches = NSMutableDictionary()
let rounds = map?["rounds"] as NSArray
for match in rounds[0] { // Error from this line
let mid = match["mid"]
let match = ["names": ["testA", "testB"]]
matches[mid] = match
}
}
答案 0 :(得分:3)
您遇到的问题是基础类在AnyObject
中处理,但对于像for
循环这样的思想不起作用:
import Foundation
let o: AnyObject = [1,2,3]
// this won't work, even though o _is_ an array
// error: type 'AnyObject' does not conform to protocol 'SequenceType'
for i in o {
}
// this is perhaps surprising given this does:
o[0] // returns 1 as an AnyObject! (that's a syntactic ! not a surprise/shock ! :)
您可能会发现更容易将之前的转换为Swift类型,然后直接使用它们。这样做的缺点是,如果要在plist中存储异构数据(即包含字符串和整数的数组)。但它看起来并不像你这样做,所以你可以像这样编写你的代码:
func startTournament() {
if let path = NSBundle.mainBundle().pathForResource("proplist", ofType: "plist") {
if let map = NSDictionary(contentsOfFile: path) {
var matches: [Int:[String:[String]]] = [:]
if let rounds = map["rounds"] as? [[[String:Int]]] {
for match in rounds[0] {
if let mid = match["mid"] {
let match = ["names": ["testA", "testB"]]
matches[mid] = match
}
}
}
}
}
}
就我个人而言,我发现这一目标更容易理解,因为您在每个级别处理的类型更容易查看和理解,而且您不会使用as?
和is
进行捣乱如果你想在同一个系列中处理多种不同的类型,那么最大的缺点是。然后你需要将AnyObject
更长一些,并在内循环中做更精细的as?
。
一旦你有了上述内容,你可以采取各种措施来更好地处理选项,并避免这么多可怕的if let
,用地图和过滤器替换循环等等,但最好还是舒服一点。这个版本第一。此外,此代码缺少可处理和报告失败案例的各种else
子句。