IOS 5 iPad Data Persistence using Archiving

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


Purchase the fully updated iOS 10 / Swift 3 / Xcode 8 edition of this book in eBook ($19.99) or Print ($45.99) format.
iOS 10 App Development Essentials Print and eBook (ePub/PDF/Kindle) edition contains over 100 chapters. Learn more...

Buy eBook 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 5 iPad application. In the chapter entitled Working with iPad Files on iOS 5 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 the iPad using a more object oriented approach known as archiving.




An Overview of Archiving

iPad iOS applications are inherently object oriented in so much as they are developed using 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 iPad’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 NSArray, NSData, NSDate, NSDictionary, NSNumber and NSString 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 iOS iPad project named archive using the Single View Application template. Once the main Xcode project window appears populated with the template files, it is time to start writing some code.


Implementing the Actions and Outlets

In order to connect the user interface objects with our back end code we will need to declare some outlets for our name, address and phone text fields and an action for the button object. We will also need an NSString variable reference to hold the path to the archive data file. With these requirements in mind, select the archiveViewController.h file from the file list in the Xcode project navigator and modify the file so that it reads as follows:

#import <UIKit/UIKit.h>

@interface archiveViewController : UIViewController 

@property (strong, nonatomic) IBOutlet UITextField *name;
@property (strong, nonatomic) IBOutlet UITextField *address;
@property (strong, nonatomic) IBOutlet UITextField *phone;
@property (strong, nonatomic) NSString *dataFilePath;
- (IBAction) saveData;
@end

Having made the appropriate declarations in the interface file, the next step is to move to the archiveViewController.m implementation file where we will synthesize the access methods for our instance variables and create a template method for the saveData action method:

#import "archiveViewController.h"

@interface archiveViewController ()

@end

@implementation archiveViewController
@synthesize name, address, phone, dataFilePath;

- (void) saveData
{
}
.
.
@end

Memory Management

Having allocated memory in implementing the above outlets, it is important that we add code to indicate that resources can be freed when the view is no longer needed. To do so, edit the archiveViewController.m file again and modify the viewDidUnload method as follows:

- (void)viewDidUnload {
        // Release any retained subviews of the main view.
        // e.g. self.myOutlet = nil;
        self.name = nil;
        self.address = nil;
        self.phone = nil;
        self.dataFilePath = nil;
}

We will need to do some more coding later but at this point it makes sense to design the user interface and establish the connections between the user interface object and the outlets and action we have declared so far.

Designing the User Interface

The user interface for our application is going to consist of three UILabels, three UITextFields and single UIButton. Select archiveViewController.xib in the main 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 37-1:


The user interface of an iPad iOS 5 data archiving example app

Figure 37-1


The next step is to establish the connections to our action and outlets. Beginning with the outlets, hold down the Ctrl key and click and drag from the File’s Owner object to the text field component located to right of the Name label object. Release the Ctrl key and mouse button and select the name outlet from the resulting menu. Repeat these steps for the address and phone text fields, connecting them to the corresponding outlets.

To connect the action, select the Save button object in the view window and display the Connections Inspector (View -> Utilities -> Show Connections Inspector). Click with the mouse within the small round circle to the right of the Touch Up Inside event and drag the blue line to the File’s Owner object. Release the mouse button and select the saveData method from the resulting menu.

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 archive 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 archiveViewController.m 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:

- (void)viewDidLoad {
 [super viewDidLoad];
 NSFileManager *filemgr;
 NSString *docsDir;
 NSArray *dirPaths;

 filemgr = [NSFileManager defaultManager];

 // Get the documents directory
 dirPaths = NSSearchPathForDirectoriesInDomains(
   NSDocumentDirectory, NSUserDomainMask, YES);

 docsDir = [dirPaths objectAtIndex:0];

 // Build the path to the data file
 dataFilePath = [[NSString alloc] initWithString: [docsDir 
        stringByAppendingPathComponent: @"data.archive"]];

 // Check if the file already exists
 if ([filemgr fileExistsAtPath: dataFilePath])
 {
         NSMutableArray *dataArray;

         dataArray = [NSKeyedUnarchiver 
          unarchiveObjectWithFile: dataFilePath];

         self.name.text = [dataArray objectAtIndex:0];
         self.address.text = [dataArray objectAtIndex:1];
         self.phone.text = [dataArray objectAtIndex: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 interface file.

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 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. If problems are encountered, check the details reported by Xcode and correct any syntax errors that may have been introduced into the code. 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 archiveViewController.m file and modify the template action method as follows:

- (void) saveData
{
     NSMutableArray *contactArray;

     contactArray = [[NSMutableArray alloc] init];
     [contactArray addObject:name.text];
     [contactArray addObject:address.text];
     [contactArray addObject: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 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 Run. The application should re-appear with the text fields primed with the contact information saved during the previous session:

The ipad iOS 5 archiving app running

Figure 37-2

Summary

Whilst data can be written to files on the iPad 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 iPad based applications.


Purchase the fully updated iOS 10 / Swift 3 / Xcode 8 edition of this book in eBook ($19.99) or Print ($45.99) format.
iOS 10 App Development Essentials Print and eBook (ePub/PDF/Kindle) edition contains over 100 chapters. Learn more...

Buy eBook Buy Print Preview Book



PreviousTable of ContentsNext
Synchronizing iPad iOS 5 Key-Value Data using iCloudiOS 5 iPad Database Implementation using SQLite