Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift unable to locate and read property list (.plist) file

Tags:

swift

I'm having a real problem in getting a simple command line OSX Swift program to read data from a simple .plist XML file - in fact the program can't even see the file despite it seemingly being present and copied into the bundle.

The data is handled by a class that is meant to read and copy the plist data into an array where it can be retrieved without the plist needing to be queried again:

//  Datadump.swift

import Foundation

class Datadump {

    //array of dictionaries containing string keys and any datatype of value
    var dataArray : Array<Dictionary<String,AnyObject>>

    init () {
        //copies data from plist
        let bundle = NSBundle.mainBundle()
        let path = bundle.pathForResource("Hardware", ofType: "plist")
        //check file located
        print("File Location: \(path)   " )
        let productArray = NSArray(contentsOfFile: path!)

        dataArray = productArray as! Array<Dictionary<String,AnyObject>>
        }

    //returns tuple based on product id
    func getData(prodId: Int) -> (String, Int) {

        //returned vars
        var price = 0
        var name : String = ""

        //iterate through array until relevant product is found
        for dict in dataArray{
            if dict["ProdId"] as! Int == prodId{
                price = dict["Price"] as! Int
                name = dict["Name"] as! String
                break
            }
        }
        return (name, price);
    }

}

However the program fails with a fatal error as soon as the:

 let productArray = NSArray(contentsOfFile: path!)

line is reached, with the output:

File Location: nil fatal error: unexpectedly found nil while unwrapping an Optional value

The print statement confirms that the program cannot find the Hardware.plist file.

The main program just creates and instance of the class and runs a function but obviously fails as soon as the init () of the class runs as mentioned above:

//  main.swift

import Foundation

//creates instance of Datadump class
var myData = Datadump ()

//queries data, copies result to tuple
let (nam, pri) = myData.getData(123)
print ("Name: \(nam)  Price: \(pri)")

The Hardware.plist file looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
    <dict>
        <key>Name</key>
        <string>Intel i7 CPU</string>
        <key>Price</key>
        <integer>13995</integer>
        <key>ProdId</key>
        <integer>123</integer>
    </dict>
    <dict>
        <key>Name</key>
        <string>19&quot; Monitor</string>
        <key>Price</key>
        <integer>9995</integer>
        <key>ProdId</key>
        <integer>456</integer>
    </dict>
    <dict>
        <key>Name</key>
        <string>8GB DDR Ram</string>
        <key>Price</key>
        <integer>4595</integer>
        <key>ProdId</key>
        <integer>789</integer>
    </dict>
</array>
</plist>

I've tried everything I can think of including looking at the settings for the .plist file and reimporting it in different ways.

Any help would be greatly appreciated!

Many thanks, Kwangle

like image 324
Kwangle Avatar asked Dec 05 '22 19:12

Kwangle


2 Answers

Normally, this is what you do:

In the Project Navigator (on the left), select the plist file. In the File Inspector (on the right), examine the target membership settings. You will probably find that the app target is not checked. This means that the plist file is not being copied into the app bundle when you build it. Check the app target, and all will be well.

But you can't do that, because this is a command line program. It is an executable and no more. There is no bundle to copy into. What you're trying to do is metaphysically impossible. 😊

like image 194
matt Avatar answered Jan 07 '23 09:01

matt


In Swift 3.0

Get .plist path

func getPath() -> String {
        let plistFileName = "fileName.plist"
        let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
        let documentPath = paths[0] as NSString
        let plistPath = documentPath.appendingPathComponent(plistFileName)
        return plistPath
}

To check whether .plist file exist or not in Documents directory.

  let plistPath = self.getPath()
        if FileManager.default.fileExists(atPath: plistPath) {
           //fileName.plist Found
        }
like image 27
Ashok R Avatar answered Jan 07 '23 09:01

Ashok R