How to Get a Plist as a Dictionary in Swift

How do I get a plist as a Dictionary in Swift?

In swift 3.0 Reading from Plist.

func readPropertyList() {
var propertyListFormat = PropertyListSerialization.PropertyListFormat.xml //Format of the Property List.
var plistData: [String: AnyObject] = [:] //Our data
let plistPath: String? = Bundle.main.path(forResource: "data", ofType: "plist")! //the path of the data
let plistXML = FileManager.default.contents(atPath: plistPath!)!
do {//convert the data to a dictionary and handle errors.
plistData = try PropertyListSerialization.propertyList(from: plistXML, options: .mutableContainersAndLeaves, format: &propertyListFormat) as! [String:AnyObject]

} catch {
print("Error reading plist: \(error), format: \(propertyListFormat)")
}
}

Read More
HOW TO USE PROPERTY LISTS (.PLIST) IN SWIFT.

iOS Framework - get plist into a dictionary

Use

let path = Bundle(identifier:"com.example.frameworkID")!.path(forResource: "properties", ofType: "plist")!

Swift 5: How to read variables in plist files?

Your property list format is not very convenient. As you want an array anyway create the property list with an array for key animals (and name all keys lowercased)





animals


name
Tiger
picture
tiger_running


name
Jaguar
picture
jaguar_sleeping




Then create two structs

struct Root : Decodable {
let animals : [Animal]
}

struct Animal : Decodable {
let name, picture : String
}

and the data source array

var animals = [Animal]()

And decode the stuff

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let url = Bundle.main.url(forResource: "Animals", withExtension:"plist")!
do {
let data = try Data(contentsOf: url)
let result = try PropertyListDecoder().decode(Root.self, from: data)
self.animals = result.animals
} catch { print(error) }
}

PropertyListDecoder and PropertyListSerialization are state of the art in Swift. The NSDictionary/NSArray API is objective-c-ish and outdated.

How to Read Plist without using NSDictionary in Swift?

The native Swift way is to use PropertyListSerialization

if let url = Bundle.main.url(forResource:"Config", withExtension: "plist") {
do {
let data = try Data(contentsOf:url)
let swiftDictionary = try PropertyListSerialization.propertyList(from: data, format: nil) as! [String:Any]
// do something with the dictionary
} catch {
print(error)
}
}

You can also use NSDictionary(contentsOf: with a type cast:

if let url = Bundle.main.url(forResource:"Config", withExtension: "plist"),
let myDict = NSDictionary(contentsOf: url) as? [String:Any] {
print(myDict)
}

but you explicitly wrote: without using NSDictionary(contentsOf...

Basically don't use NSDictionary without casting in Swift, you are throwing away the important type information.



Meanwhile (Swift 4+) there is still more comfortable PropertyListDecoder which is able to decode Plist directly into a model.

Reading a PLIST file Dict of Dict

Try setting the format of the dictionary explicitly if you are only working with a nested dictionary that is of type [String:String]:

let dataFromPlist = try PropertyListSerialization.propertyList(from: data, format: nil) as! [String : [String : String ] ]

Based on your sample data, I created a property list whose source file converts to this in xml:





Name

Age
Two
Height
Short



The output is as you would like:

["Name": ["Height": "Short", "Age": "Two"]]

The full example code with an Example.plist file in the root of the project:

let urlPath = Bundle.main.url(forResource: "Example", withExtension: "plist")
if let urlPath = urlPath {
do {
let data = try Data(contentsOf: urlPath)
let dataFromPlist = try PropertyListSerialization.propertyList(from: data, format: nil) as! [String : [String : String ] ]
print(dataFromPlist)
} catch {
print(error)
}
}
}

How do I get content of a plist file in swift?

You can use the function url(forResource:withExtension:) instead of the path. You can use this function (replace MyPlistFile.plist with the name of your file):

// Provide the key of the entry you need to read
func getStringValueFromPlist(forKey key: String) -> String {
guard let fileURL = url(forResource: "MyPlistFile.plist", withExtension: nil) else {
fatalError("Can't find \(fileName)")
}

let contents = NSDictionary(contentsOf: fileURL) as? [String: String] ?? [:]

return contents[key] ?? ""
}

To get a nested dictionary, you need to change the type, from String to a dictionary type, like [String: String], then read inside that dictionary.

Swift 4: Adding dictionaries to Plist

NSKeyedUnarchiver is the wrong way to save property lists.

There is a dedicated struct PropertyListSerialization to load and save property lists.

First declare a computed property plistURL

var plistURL : URL {
let documentDirectoryURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
return documentDirectoryURL.appendingPathComponent("dictionary.plist")
}

and two methods for loading and saving

func savePropertyList(_ plist: Any) throws
{
let plistData = try PropertyListSerialization.data(fromPropertyList: plist, format: .xml, options: 0)
try plistData.write(to: plistURL)
}


func loadPropertyList() throws -> [String:String]
{
let data = try Data(contentsOf: plistURL)
guard let plist = try PropertyListSerialization.propertyList(from: data, format: nil) as? [String:String] else {
return [:]
}
return plist
}

Create the dictionary and save it

do {
let dictionary = ["key1" : "value1", "key2":"value2", "key3":"value3"]
try savePropertyList(dictionary)
} catch {
print(error)
}

To update a value read it, update the value and save it back

do {
var dictionary = try loadPropertyList()
dictionary.updateValue("value4", forKey: "key4")
try savePropertyList(dictionary)
} catch {
print(error)
}

How to add Dictionary to Plist in SWIFT

You need to convert Dictionary to NSDictionary so that you can use writeToFile

Try to cast with this

let succeed = (favoriteGooglelocations as NSDictionary).writeToFile(path, atomically: true)

If succeed is false,check your GoogleItems class,it should conforms to NSCoding

Update,this is the code I test,you may refer to it

import UIKit
import CoreLocation

Set you GoogleItems conforms to NSCoding

class GoogleItems: NSObject,NSCoding {
override init() {}
var name:String?
var address:String?
var distance : String?
var googleLocation: CLLocation?
var isStar : Bool?
required init(coder aDecoder: NSCoder) {
self.name = aDecoder.decodeObjectForKey("name") as? String
self.address = aDecoder.decodeObjectForKey("address") as? String
self.distance = aDecoder.decodeObjectForKey("distance") as? String
self.googleLocation = aDecoder.decodeObjectForKey("googleLocation") as? CLLocation
self.isStar = aDecoder.decodeObjectForKey("isStar") as? Bool
}
func encodeWithCoder(aCoder: NSCoder) {
if name != nil{ aCoder.encodeObject(name, forKey: "name")}
if address != nil{ aCoder.encodeObject(address, forKey: "address")}
if distance != nil { aCoder.encodeObject(distance, forKey: "distance")}
if googleLocation != nil { aCoder.encodeObject(googleLocation, forKey: "googleLocation")}
if isStar != nil {aCoder.encodeBool(isStar!, forKey: "isStar")}
}
}

Then write to file

    var favoriteGooglelocations = [Int:GoogleItems]()
var item = GoogleItems()
item.isStar = true
item.name = "name"
item.address = "address"
item.googleLocation = nil
item.distance = "23"
favoriteGooglelocations[1] = item
let dic = favoriteGooglelocations as NSDictionary
let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let documentDirectory = paths[0] as! String
let path = documentDirectory.stringByAppendingPathComponent("Favorites.plist")
let succeed = NSKeyedArchiver.archiveRootObject(dic, toFile: path)
println(succeed)

Read from file

     let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)

let documentDirectory = paths[0] as! String

let path = documentDirectory.stringByAppendingPathComponent("Favorites.plist")
let dic = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as? [Int:GoogleItems]
if(dic != nil){
for (key,value) in dic!{
let item = value
println(item.name)
println(item.address)
}

}


Related Topics



Leave a reply



Submit