I have created a property list with continents, countries, and random facts as shown below:
I can access the top level keys from the property list easily enough:
if let path = NSBundle.mainBundle().pathForResource("countryData", ofType: "plist") {
dict = NSDictionary(contentsOfFile: path)
}
countries += dict!.allKeys as! [String]
If I wanted to access the second element in the vanuatu array, however, things fall apart. I would think objectForKey would get the country dictionary and then use objectForKey again to get the country array. But so far, that hasn't worked. At all...
if let path = NSBundle.mainBundle().pathForResource("countryData", ofType: "plist") {
dict = NSDictionary(contentsOfFile: path)
if let australia = dict["australia"] as? [String:AnyObject]{
// access the second element's property here
if let vanuatu = australia["vanuatu"] as? [String]{
// Access the vanuatu here
}
}
}
if let path = NSBundle.mainBundle().pathForResource("Property List", ofType: "plist") {
dict = NSDictionary(contentsOfFile: path)
if let vanuatu = dict.objectForKey("australia") as? [String:AnyObject]{
if let vanuatuArray = vanuatu["vanuatu"] as? [String]{
print(vanuatuArray[1])
}
}
}
You can get data from plist file like that.
I have created a plist file for countryCodes.
func fetchCounrtyCodes() -> [CountryCodes]{
let name = "name"
let dial_code = "dial_code"
let code = "code"
var countryArray = [CountryCodes]()
guard let filePath = NSBundle.mainBundle().pathForResource("CountryList", ofType: "json") else {
print("File doesnot exist")
return []
}
guard let jsonData = NSData(contentsOfFile: filePath) else {
print("error parsing data from file")
return []
}
do {
guard let jsonArray = try NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.AllowFragments) as? [[String:String]] else {
print("json doesnot confirm to expected format")
return []
}
countryArray = jsonArray.map({ (object) -> CountryCodes in
return CountryCodes(name: object[name]!, dial_code:object[dial_code]!, code: object[code]!)
})
}
catch {
print("error\(error)")
}
return countryArray
}
struct CountryCodes{
var name = ""
var dial_code = ""
var code = ""
}
Related
I'm trying to read a text file and return an array of dictionary in swift
the text file has the following data:
13582;Name 1;12345;5
13583;Name 2;23456;5
13585;Name 3;EX934;6
13598;Name 4;XE345_c;6
13600;Name 5;XF8765;6
func machineNumberToName() -> [[String: String]] {
var dic1 = [String: String]()
var dic2 = [String: String]()
var dic3 = [String: String]()
var dic4 = [String: String]()
// FileName for machines
let fileName = "Machines.txt";
if let path = Bundle.main.path(forResource: fileName, ofType: nil) {
do {
let contents = try! String(contentsOfFile: path)
let lines = contents.split(separator: "\n")
for line in lines {
var entries = lines.split(separator: ";")
dic1["machineNumber"] = entries[0]
dic2["machineName"] = entries[1]
dic3["machineXML"] = entries[2]
dic4["wifi"] = entries[3]
return [dic1, dic2, dic3, dic4]
}
} catch {
print(error.localizedDescription)
}
} else {
NSLog("file not found: \(fileName)")
return []
}
}
however I get the error
Cannot assign value of type 'Array<String.SubSequence>.SubSequence' (aka 'ArraySlice<Substring>') to subscript of type 'String'
Not sure what I'm doing wrong!
entries is not an array of String, it is an array of ArraySlice<Substring>, or informally an array of substrings.
You can use String(entries[0]) to get a string to put in your dictionary.
You have another problem though; You will only end up with the first line in the dictionaries, since you return out of the loop. Even if you fix that, returning an array of dictionaries is icky. Create an appropriate struct and return an array of those structs
struct MachineDetails {
let machineNumber: String
let machineName: String
let machineXML: String
let machineWiFi: String
}
func getMachineDetails() -> [MachineDetails] {
var details = [MachineDetails]()
let fileName = "Machines.txt";
if let path = Bundle.main.path(forResource: fileName, ofType: nil) {
do {
let contents = try String(contentsOfFile: path)
let lines = contents.split(separator: "\n")
for line in lines {
let entries = line.split(separator: ";").map { String($0) }
if entries.count == 4 {
let newMachine = MachineDetails(machineNumber:entries[0],
machineName:entries[1],
machineXML:entries[2],
machineWiFi:entries[3])
details.append(newMachine)
} else {
print("Malformed line \(line)")
}
}
} catch {
print(error.localizedDescription)
}
} else {
NSLog("file not found: \(fileName)")
}
return details
}
How to fetch .plist / property list content and show in swift 4.2
// 1. Forming resource URL of property list file
// 2. getting Data from url
// 3.serializing plist data to NSObject type classess .
1.guard let plistUrl = Bundle.main.url(forResource: "Your property- list file name ", withExtension: "plist"),
2.let plistData = try? Data(contentsOf: plistUrl) else { return nil }
var plistEntries: [[String: Any]]? = nil
do {
3. plistEntries = try PropertyListSerialization.propertyList(from: plistData, options: [], format: nil) as? [[String: Any]]
} catch {
print("error reading plist")
}
for property in plistEntries {
guard let property1 = property["key-name"] as? String,
let property2 = property["key-name"] as? NSNumber
else { fatalError("Error reading data") }
print("value: \(property1)")
print("value: \(property2)")
}
I have an App written in Swift 3.0 and I declared the following data types:
var movies = [Movie]()
var getPlist = NSMutableDictionary()
var movieItems = NSMutableDictionary()
And I have the following method which is loading the content of a plist:
// Connect to plist and get the data
if let plist = PlistHandler(name: "MovieData") {
getPlist = plist.getMutablePlistDict()!
// Load the movie items into the table view data source
for i in 0..<getPlist.count {
movieItems = (getPlist.object(forKey: "Item\(i)") as! NSMutableDictionary) as! [String: String] as! NSMutableDictionary
let newName = movieItems.object(forKey: "Name")
let newRemark = movieItems.object(forKey: "Remark")
if newName as? String != "" {
movies.append(Movie(name: newName as? String, remark: newRemark as? String)
)}
}
} else {
print("Unable to get Plist")
}
It calls a method called getMutablePlistDict() from another class:
// Get the values from plist -> MutableDirectory
func getMutablePlistDict() -> NSMutableDictionary? {
let fileManager = FileManager.default
if fileManager.fileExists(atPath: destPath!) {
guard let dict = NSMutableDictionary(contentsOfFile: destPath!) else { return .none }
return dict
} else {
return .none
}
}
When I run the App I get the error above (see question title). But this is new. In Xcode 8 I didn't get this error. What is the reason for this and how I have to change my code to avoid that?
You can use like this :
Changed NSMutableDictionary to [String: Any] :
var movies = [Movie]()
var getPlist: [String: Any] = [:]
var movieItems: [String: Any] = [:]
func getMutablePlistDict() -> [String: Any] {
let fileManager = FileManager.default
if fileManager.fileExists(atPath: destPath!) {
if let dict = NSDictionary(contentsOfFile: destPath!) as? [String: Any] {
return dict
}
} else {
return [:]
}
}
if let plist = PlistHandler(name: "MovieData") {
let getPlist = plist.getMutablePlistDict()
// Load the movie items into the table view data source
for i in 0..<getPlist.count {
if let movieItemsCheck = getPlist["Item\(i)"] as? [String: Any] {
movieItems = movieItemsCheck
if let newName = movieItems["Name"] as? String, let newRemark = movieItems["Remark"] as? String, newName != "" {
movies.append(Movie(name: newName, remark: newRemark))
}
}
}
} else {
print("Unable to get Plist")
}
I am using this code to filter for certain strings in my plist array:
func SearchC(){
let pathMC = NSBundle.mainBundle().pathForResource("myPlistArray", ofType: "plist")
let dictMC = NSDictionary(contentsOfFile: pathMC!)
myPlistArray = dictMC!["Questions"]!.mutableCopy() as? Array
if let questionArray = myPlistArray as? [[String:AnyObject]] {
let answersC = questionArray.filter({
if let correct = $0["CorrectAnswer"] as? String {
return correct.uppercaseString == "C"
}
return false
})
print("\(answersC)")
}
}
I now need to filter for items which have the boolean value of “YES”, or “NO”. I tweaked the code above and came up with the following:
func SearchYES(){
let pathMC = NSBundle.mainBundle().pathForResource("myPlistArray", ofType: "plist")
let dictMC = NSDictionary(contentsOfFile: pathMC!)
myPlistArray = dictMC!["Questions"]!.mutableCopy() as? Array
if let questionArray = myPlistArray as? [[String:AnyObject]] {
let isFavorite = questionArray.filter({
if let favorite = $0["isFavorite"] as? String {
return favorite.uppercaseString == "YES"
}
return false
})
print("\(isFavorite)")
}
}
BUT it’s not working. Does anyone know how to filter items which have a boolean key value of TRUE/YES?
This is part my code. But myDict is nil. The filename is right.I already checked for many times.
var myDict: NSDictionary?
if let path = NSBundle.mainBundle().pathForResource("CatData", ofType: "plist") {
myDict = NSDictionary(contentsOfFile: path)
}
if let dict = myDict {
print("print something")
}
your plist is array of dictionary so try
var myArray: NSArray?
if let path = NSBundle.mainBundle().pathForResource("Categories", ofType: "plist") {
myArray = NSArray(contentsOfFile: path)
}
if let array = myArray {
for item: AnyObject in array {
if let item = item as? NSDictionary {
if let categoryTitle = item["CategoryTitle"] as? NSString {
print("categoryTitle = ", categoryTitle)
}
if let imageNames = item["ImageNames"] as? NSArray {
print("imageNames = ", imageNames)
}
}
}
}
Providing your file name is correct, and your plist has been added to the bundle:
You need to make sure your file is the type you're expecting.
For example. The root of your plist is an Array, and you're looking to get a Dictionary out of it.
So lets rewrite your code:
var myArray: Array? {
if let path = NSBundle.mainBundle().pathForResource("CatData", ofType: "plist") {
myArray = NSArray(contentsOfFile: path) as! [[String:AnyObject]]
}
if let array = myArray {
print("print something")
}
}