Search code examples
iosswiftnsdictionaryfor-in-loopswift-optionals

Loop through plist in swift


Hey guys I'm currently trying to loop through a plist that is set up like this:

enter image description here

The code I'm using:

    letterPoints = NSDictionary(contentsOfFile: Bundle.main.path(forResource: "LetterPoints", ofType: "plist")!)

    for (myKey, myValue) in letterPoints {
        for (key, value) in myValue as NSDictionary {
            let x = value["Item 0"] as NSNumber
            let y = value["Item 1"] as NSNumber
            // lastPoint: CGPoint = CGPoint(x: x.integerValue, y: y.integerValue)
            println("x: \(x); y: \(y)")
        }
    }

However I am getting and error in the first line of the loop: for-in loop requires 'NSDictionary?' to conform to 'Sequence'; did you mean to unwrap optional?

I took the code from loop through nested NSDictionary in plist using swift and it seems to be the same structured plist as mine so im not sure why it isn't working. What is the best way to loop over my plist?


Solution

  • First of all do not use the NSDictionary/NSArray API to read property lists in Swift at all.

    NSDictionary(contentsOfFile returns an optional, you have to unwrap it to use it in a loop, that's what the error is telling you.

    And there is no dictionary but the root object in the property list. All other collection types are arrays (clearly stated in the screenshot)

    The highly recommended API to read property lists in Swift is PropertyListSerialization or even PropertyListDecoder in Swift 4+

    let url = Bundle.main.url(forResource: "LetterPoints", withExtension: "plist")!
    let data = try! Data(contentsOf: url)
    let letterPoints = try! PropertyListSerialization.propertyList(from: data, format: nil) as! [String:[[Int]]]
    for (_, outerArray) in letterPoints {
        for innerArray in outerArray {
            let x = innerArray[0]
            let y = innerArray[1]
            print("x: \(x); y: \(y)")
        }
    }
    

    As the property list is (immutable) in the application bundle force unwrapping the optionals is fine. If the code crashes it reveals a design mistake which can be fixed at once.