我有一个 plist,其设置如下所示:
我想将它加载到一个变量中,然后遍历每个项目。这是我目前的代码,但无济于事,我看到错误“Type 'AnyObject' does not conform to protocol '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
}
}
请您参考如下方法:
您遇到的问题是基础类处理 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 子句。
