Reputation: 1385
I have a plist that is set up as shown below:
I'd like to load this into a variable and then loop over each of the items. This is the code I have so far, but to no avail I am seeing the error "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
}
}
Upvotes: 1
Views: 1644
Reputation: 40965
The problem you are having is that the foundation classes deal in AnyObject
s, but for thinks like for
loops that doesn't work:
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 ! :)
You may find it easier to convert earlier to Swift types and then use them directly. The downside of this is if you are storing heterogenous data in your plist (i.e. an array that has both strings and integers in it). But it doesn't look you do, so you could write your code like this:
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
}
}
}
}
}
}
Personally, I find this much easier to understand at a glance because the types you are dealing with at each level are easier to see and understand and you're not mashing away with as?
and is
etc. The big downside to this is if you want to handle multiple different types within the same collection. Then you need to leave things as AnyObject
a bit longer, and do more fine-grained as?
in the inner loops.
Once you have the above, there are various tricks you can do to handle the optionals better and avoid so many horrid if let
s, replace loops with maps and filters etc., but it's probably better to get comfortable with this version first. Also, this code is missing various else
clauses that could handle and report failure cases.
Upvotes: 3