Search code examples
arraysswiftproperty-list

Decode data from PropertyList


I want to fetch data from property list and the structure of the property list is like this

plist data

this is the source file as xml

<array>
    <dict>
        <key>imageIcon</key>
        <string>air-compressor.png</string>
        <key>toolsName</key>
        <string>Air Compressor</string>
        <key>items</key>
        <array>
            <dict>
                <key>item</key>
                <string>Air Compressor 1</string>
                <key>borrower</key>
                <string></string>
            </dict>
            <dict>
                <key>item</key>
                <string>Air Compressor 2</string>
                <key>borrower</key>
                <string></string>
            </dict>
        </array>
    </dict>
</array>
</plist>

and I structure my object model like this

struct ToolsItem: Codable {
    var tools: [Tools]
}

struct Tools: Codable {
    let imageIcon: String
    let toolsName: String
    var items: [Items]
}

struct Items: Codable {
    let itemName: String
    let borrower: String
}

and set my data manager like this

class DataManager {
    
    static let shared = DataManager()
    
    func fetch() {
        guard let path = Bundle.main.path(forResource: "ToolsData", ofType: "plist") else { return }
        let url = URL(fileURLWithPath: path)
        
        do {
            let data = try Data(contentsOf: url)
            
            let items = try PropertyListDecoder().decode(ToolsItem.self, from: data)
            print(items.tools)
        } catch {
            print(error)
        }
        
    }
}

but it return

"Expected to decode Dictionary<String, Any> but found an array instead." and no data being show.

if change my data manager like this

let items = try PropertyListDecoder().decode([ToolsItem].self, from: data)

The error return

keyNotFound(CodingKeys(stringValue: "tools", intValue: nil), Swift.DecodingError.Context(codingPath: [_PlistKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: "tools", intValue: nil) ("tools").", underlyingError: nil))

How to fetch data from plist correctly?


Solution

  • Your struct should be the following.

    import Foundation
    
    struct ToolsItem: Codable {
        let imageIcon: String
        let toolsName: String
        let items: [Items]
    }
    
    struct Items: Codable {
        let item: String
        let borrower: String
    }
    

    // For the view controller //

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        if let path = Bundle.main.path(forResource: "ToolsData", ofType: "plist") {
            let fileURL = URL(fileURLWithPath: path)
            do {
                let data = try Data(contentsOf: fileURL)
                let items = try PropertyListDecoder().decode([ToolsItem].self, from: data)
                print("Items: \(items)")
            } catch let error as NSError {
                print("\(error)")
            }
        }
    }