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" 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
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. 😊
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With