A property list is an XML key-value store that allows applications to store small amounts of data locally. Property lists are best suited to storing small amounts of data (less than a few hundred kilobytes). It is quite common for applications to use property lists to store application configuration information, such as server addresses and URLs.
A property list can be created using the property list editor, or programmatically. The GUI property list editor that is integrated with XCode displays a property list file as a hierarchy of nodes and elements, all contained under a root node (see Figure 22.1). The root node can be either an array or a dictionary.
To create a property list, add a new file to the project and select Property List from the iOS Resource section in the file options dialog box (see Figure 22.2).
This will add an empty property list file to your project, with a single dictionary element called Root (see Figure 22.3).
To add a new entry to the property list, select the parent node and select Editor Add Item (see Figure 22.4).
The default data type for new items is String
; you can change that using the drop-down picker in the second column. If the parent node is a dictionary, then each child is treated as a key-value pair with keys being unique Strings.
To create a property list programmatically, you need to build a dictionary or array with data you wish to save and write it to a file in your application's documents directory. The following code snippet shows how you can achieve this:
func writeToPlist(fileName:String!, data:NSMutableDictionary!)
{
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,
.UserDomainMask, true)[0] as String
let path = paths.stringByAppendingPathComponent(fileName)
data.writeToFile(path, atomically: true)
}
If all the data you wish to write to a property list file can be represented using a combination of NSNumber
, NSString
, NSArray
, NSDictionary
, and NSData
instances, then your task is straightforward. If, however, you wish to write instances of your own classes to a property list file, you must implement the NSCoding
protocol.
NSCoding
defines two methods encodeWithCoder(aCoder: NSCoder)
and a designated initializer init?(coder aDecoder: NSCoder)
.
The following code snippet lists a class Employee that is NSCoding
-compliant and can be inserted into a property list.
import UIKit
class Employee: NSObject, NSCoding {
var name:String?
var address:String?
func encodeWithCoder(aCoder: NSCoder)
{
// write to plist here.
aCoder.encodeObject(name)
aCoder.encodeObject(address)
}
required init?(coder aDecoder: NSCoder)
{
// read from plist here
name = aDecoder.decodeObjectForKey("name") as? String
address = aDecoder.decodeObjectForKey("address") as? String }
}
To read a property list file, you need to load its contents into an array or dictionary. The following code snippet assumes you have added a property list file called Config.plist
to the project:
var plistDictionary: NSDictionary?
if let path = NSBundle.mainBundle().pathForResource("Config", ofType: "plist") {
plistDictionary = NSDictionary(contentsOfFile: path)
}
if let unwrappedDictionary = pListDictionary {
// Use unwrappedDictionary here
}
In this Try It, you create a simple iPhone application based on the Single View Application template called PropertyListTest that populates a table view with contents read off a plist file. The contents of the plist file will be generated programmatically.
PropertyListTest
.
UITableView
instance to the default scene.
prototypeCell1
.AppDelegate.swift
file in the project explorer.application(application, didFinishLaunchingWithOptions) -> Bool
withfunc application(application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [NSObject: AnyObject]?) -> Bool {
// create contacts.plist in the documents directory, if it does not
exist
let fileManager:NSFileManager! = NSFileManager.defaultManager()
let documentsDirectory:String =
NSSearchPathForDirectoriesInDomains(
NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.
UserDomainMask,
true)[0] as String
let plistPath = documentsDirectory + "/contacts.plist"
if fileManager.fileExistsAtPath(plistPath) == false {
let contacts:NSMutableArray = NSMutableArray()
contacts.addObject("Elana")
contacts.addObject("Sonam")
contacts.addObject("Jane")
contacts.addObject("Paul")
contacts.addObject("Abhishek")
contacts.addObject("Nick")
contacts.addObject("Steve")
contacts.writeToFile(plistPath, atomically: true)
}
return true
}
ViewController.swift
file in the project explorer.var arrayOfContacts:NSArray? = nil
viewDidLoad
method with the following:override func viewDidLoad() {
super.viewDidLoad()
// load contacts.plist into arrayOfContacts
let documentsDirectory:String =
NSSearchPathForDirectoriesInDomains(
NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.
UserDomainMask,
true)[0] as String
let plistPath = documentsDirectory + "/contacts.plist"
arrayOfContacts = NSArray(contentsOfFile: plistPath)
}
numberOfSectionsInTableView
data source method as follows:func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1;
}
numberOfRowsInSection
data source method as follows:func tableView(tableView: UITableView,
numberOfRowsInSection section: Int) -> Int
{
return arrayOfContacts!.count
}
cellforRowAtIndexPath
data source method as follows:func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("prototypeCell1",
forIndexPath: indexPath) as UITableViewCell
let contactName:String =
arrayOfContacts!.objectAtIndex(indexPath.row)
as! String
cell.textLabel?.text = contactName
return cell
}
ViewController
class to inherit from UIViewController
, UITableViewDataSource
, and UITableViewDelegate
:class ViewController: UIViewController,
UITableViewDataSource,
UITableViewDelegate {
Test your app in the iOS Simulator.
Click the Run button in the Xcode toolbar. Alternatively, you can select Project Run.