iOS 8 Swift Read Plist
You may be looking for something like this:
let path = NSBundle.mainBundle().pathForResource("savedState", ofType: "plist")
let dict = NSDictionary(contentsOfFile: path!)
let players = dict.valueForKey("players") as? String
let level = dict.valueForKey("level") as? String
let numPlayers = players != nil ? players!.toInt() : 0
let playLevel = level != nil ? level!.toInt() : 0
It attempts to read players and level from the plist as optional strings, then if they are non nil it sets numPlayers and playLevel to their Int value. If they are nil numPlayers and playLevel are set to 0. Although if your plist values are integers, why not just read them as Ints?
let players = dict.valueForKey("players") as? Int
let level = dict.valueForKey("level") as? Int
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.
How can I read data from a PLIST in Swift?
First, your Root
object in the plist is an NSArray
not a NSDictionary
.
Second, if you want to use KVC on Foundation Collections (I don't believe this works with Swift's Array) you need to call valueForKeyPath
.
let chapterPath = NSBundle.mainBundle().pathForResource("chapterMapping", ofType: "plist")
if let arrayOfItems: [AnyObject] = NSArray(contentsOfFile: chapterPath!) {
let chapterNames: [String] = arrayOfItems.valueForKeyPath("chapterName") as NSArray as [String]
let pageNumbers: [Int] = arrayOfItems.valueForKeyPath("pageNumber") as NSArray as [Int]
}
Third, the swift-y way of doing this would be with the map
function, but arrayOfItems
would need to be a strongly-defined type and it might be more work than it's worth. Example:
let array: [ChapterMetaData] = // define it here
let chapterImages = array.map { $0.chapterImage }
How can I read Plist in Swift?
Your method signature clearly states that it returns an [Any]
(i.e., Swift native Array
containing elements of any type whatsoever), while you try to cast the return value into NSArray
(even though it already is by virtue of intialization: NSArray(contentsOfFile:)
).
Change it to:
return arry as? [Any]
// (will return nil if the cast fails - not a problem if you
// also apply the fix mentioned below...)
The other path tries to return nil
; for that to be acceptable, your signature needs to be defined as returning an optional:
func loadPlistArray() -> [Any] // WRONG
func loadPlistArray() -> [Any]? // RIGHT
EDIT: If your app is structured in such a way that you can't afford to return nil
from your method, you can instead return an empty array on failure:
else {
return [] // Empty array
}
(use [:]
for empty dictionary)
Also, try to avoid using !
whenever possible, and switch to ?
instead, unless you are 100% sure that whatever it is you are forcing will not fail and cause a runtime error (crash).
Read plist in swift 3 playground
To finally get the program working I used.
devices = NSArray(contentsOfFile: path) as! [AnyObject]
The issue with playground continuously running was solved by going to activity monitor and force quitting the process named com.apple.coresimulator which was identified as not responding. After doing this the playground ran instantly.
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.
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.
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)
<?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">
<dict>
<key>animals</key>
<array>
<dict>
<key>name</key>
<string>Tiger</string>
<key>picture</key>
<string>tiger_running</string>
</dict>
<dict>
<key>name</key>
<string>Jaguar</string>
<key>picture</key>
<string>jaguar_sleeping</string>
</dict>
</array>
</dict>
</plist>
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.
Related Topics
Auto-Sizing Uicollectionview Headers
Swift - Uipopovercontroller in iOS 8
(Swift Spritekit) Rotate Sprite in the Direction of Touch
Shift Avplayer Captions When Subview Overlaps Them
Apple Push Notifications in Tvos
Getting Uiwebview API Deprecation Message After Adding Paypal Pod in My iOS App
Swift Lazy and Optional Properties
Correct Way to Layout Swiftui (Similar to Autolayout)
How to Schedule a Same Local Notification in Swift
How Do View Types Like Text or Image Conform to the View Protocol in Swiftui
iOS How to Correctly Handle Orientation When Capturing Video Using Avassetwriter
iOS Swift 2 Record Video Avcapturesession
Geolocation by Iphone's Ip Address
Core Data Taking Time to Insert Records with Fetching Entity & Set as Relationship