IOS 8 Data Persistence using Archiving and Swift

From Techotopia
Jump to: navigation, search
PreviousTable of ContentsNext
Synchronizing iOS 8 Key-Value Data using iCloudSwift iOS 8 Database Implementation using SQLite


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book


In the previous chapters of this book we have looked at some basic file and directory handling operations which can be performed within an iOS 8 application. In the chapter entitled Working with Files in Swift on iOS 8 we looked at creating files and reading and writing data from within an iOS application before looking at iCloud based storage in subsequent chapters. In this chapter we will look at another form of data persistence on iOS 8 using a more object oriented approach known as archiving.


Contents


An Overview of Archiving

iOS applications are inherently object oriented in so much as they are developed using Swift or Objective-C and consist of any number of objects designed to work together to provide the required functionality. As such, it is highly likely that any data created or used within an application will be held in memory encapsulated in an object. It is also equally likely that the data encapsulated in an object may need to be saved to the device’s file system so that it can be restored on future invocations of the application. One approach might be to write code that extracts each data element from an object and writes it to a file. Similarly, code would need to be written to read the data from the file, create an instance of the original object and then assign the data to that object accordingly. Whilst this can be achieved, it can quickly become complex and time consuming to implement.

An alternative is to use a mechanism called archiving. Archiving involves encoding objects into a format that is written to a file. Data may subsequently be decoded (or unarchived) and used to automatically rebuild the object. This concept is somewhat analogous to serialization as supported by languages such as Java.

A number of approaches to archiving are supported by the Foundation Framework. Arguably the most flexible option is that provided by the NSKeyedArchiver class. This class provides the ability to encode an object into the form of a binary property list that is written to file and may subsequently be decoded to recreate the object using the NSKeyedUnarchiver class.

An alternative option is to use the writeToFile:anatomically method available with a subset Foundation class. This mechanism writes the object data to file in the form of an XML property list file. This approach, however, is limited to array, dictionary, string, NSData, NSDate and NSNumber based objects.

In the remainder of this chapter we will work through an example of archiving using the NSKeyedArchiver and NSKeyedUnarchiver classes.

The Archiving Example Application

The end product of this chapter is an application that prompts the user for a name, address and phone number. Once this data has been entered, pressing a button causes the contact data to be stored in an array object which is then archived to a binary property file. On a subsequent reload of the application this data is unarchived and used to recreate the array object. The restored data is then extracted from the array object and presented to the user.

Begin by launching Xcode and create a new project named Archive using the Single View Application template. Select Universal from the device menu and choose Swift as the programming language. Once the main Xcode project window appears populated with the template files, it is time to start developing the application.


Designing the User Interface

The user interface for our application is going to consist of three Labels, three TextFields and a single Button. Select Main.storyboard in the Xcode project navigator and display the Object Library panel (View -> Utilities -> Show Object Library) if it is not already visible. Drag, drop, resize, position and configure objects on the View window canvas until your design approximates that illustrated in Figure 40-1:

Ios 8 archive ui.png

Figure 40-1


The next step is to establish the connections to our action and outlets.

Select the top most text field object in the view canvas, display the Assistant Editor panel and verify that the editor is displaying the contents of the ViewController.swift file. Ctrl-click on the text field object and drag to a position just below the class declaration line in the Assistant Editor. Release the line and in the resulting connection dialog establish an outlet connection named name.

Repeat the above steps to establish outlet connections for the remaining text fields to properties named address and phone respectively.

Ctrl-click on the button object and drag the line to the area immediately beneath the viewDidLoad method in the Assistant Editor panel. Release the line and, within the resulting connection dialog, establish an Action method on the Touch Up Inside event configured to call a method named saveData.

Close the Assistant Editor, select the ViewController.swift file and add an additional variable to store a reference to the path to the archive data file:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var name: UITextField!
    @IBOutlet weak var address: UITextField!
    @IBOutlet weak var phone: UITextField!

    var dataFilePath: String?
.
.
.

Checking for the Existence of the Archive File on Startup

Each time the application is launched by the user, the code will need to identify whether the archive data file exists from a previous session. In the event that it does exist, the application will need to read the contents to recreate the original array object from which the archive was created. Using this newly recreated array object, the array elements will then be extracted and used to populate the name, address and phone text fields.

The traditional location for placing such initialization code is in the viewDidLoad method of the view controller class. Within the project window, therefore, select the ViewController.swift file and scroll down the contents of this file until you reach the viewDidLoad method. Having located the method, modify it as outlined in the following code fragment:

override func viewDidLoad() {
    super.viewDidLoad()

    let filemgr = NSFileManager.defaultManager()
    let dirPaths = 
		NSSearchPathForDirectoriesInDomains(.DocumentDirectory, 
					.UserDomainMask, true)

    let docsDir = dirPaths[0] as! String
    dataFilePath = 
		docsDir.stringByAppendingPathComponent("data.archive")

    if filemgr.fileExistsAtPath(dataFilePath!) {
       let dataArray = 
		NSKeyedUnarchiver.unarchiveObjectWithFile(dataFilePath!) 
						as! [String]
        name.text = dataArray[0]
        address.text = dataArray[1]
        phone.text = dataArray[2]
    }
}

Within this method a number of variables are declared before creating an instance of the NSFileManager class.

A call is then made to the NSSearchPathForDirectoriesInDomains function and the path to the application’s Documents directory extracted from the returned array object. This path is then used to construct the full pathname of the archive data file, which in turn is stored in the dataFilePath instance variable we previously added to the view controller class.

Having identified the path to the archive data file, the file manager object is used to check for the existence of the file. If it exists, the file is “unarchived” into a new array object using the unarchiveObjectWithFile method of the NSKeyedUnarchiver class. The data is then extracted from the array and displayed in the corresponding text fields.

With this code implemented, select the Xcode run toolbar button to compile and execute the application in the simulator. Assuming no problems are encountered, the next step is to implement the action method. Once the app has launched successfully, exit from the iOS Simulator and return to the main Xcode project window.

Archiving Object Data in the Action Method

The Save button in the user interface design is connected to the saveData method of the view controller class. Edit the ViewController.swift file and modify the template action method as follows:

@IBAction func saveData(sender: AnyObject) {
    var contactArray = [name.text, address.text, phone.text]
    NSKeyedArchiver.archiveRootObject(contactArray, 
					toFile: dataFilePath!)
}

When triggered, this method creates a new array and assigns the content of each text field to an element of that array. The array object is then archived to the predetermined data file using the archiveRootObject method of the NSKeyedArchiver class. The instance data of the array object is now saved to the archive ready to be loaded next time the application is executed.

Testing the Application

Save the code changes and build and run the application on a device or in the simulator environment. Enter a name, address and phone number into the respective text fields and press the save button. Stop the application by clicking the stop button located in the Xcode toolbar and then relaunch the application by clicking the run button. The application should re-appear with the text fields primed with the contact information saved during the previous session:


Ios 8 archive app running.png

Figure 40-2


Summary

Whilst data can be written to files on an iOS device using a variety of mechanisms, archiving provides the ability to save the instance data of an object to file at a particular point and then restore the object to that state at any time in the future. This provides an object-oriented approach to data persistence on iOS based applications.


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book



PreviousTable of ContentsNext
Synchronizing iOS 8 Key-Value Data using iCloudSwift iOS 8 Database Implementation using SQLite