Synchronizing iPhone iOS 5 Key-Value Data using iCloud

PreviousTable of ContentsNext
Using iCloud Storage in an iOS 5 iPhone ApplicationiOS 5 iPhone Data Persistence using Archiving


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


When considering the use of iCloud in an application it is important to note that the Apple ecosystem is not limited to the iPhone platform. In fact, it also encompasses the iPad and a range of Mac OS X based laptop and desktop computer systems, all of which have access to iCloud services. This increases the chance that a user will have the same app in one form or another on a number of different devices and platforms. Take, for the sake of an example, a hypothetical news magazine application. A user may have an instance of this application installed on both an iPhone and an iPad. If the user begins reading an article on the iPhone instance of the application and then switches to the same app on iPad at a later time the iPad application should take the user to the position reached in the article on the iPhone so that the user can resume reading.

This kind of synchronization between applications is provided by the Key-Value data storage feature of iCloud. The goal of this chapter is to provide an overview of this service and work through a very simple example of the feature in action in an iPhone iOS 5 application.

An Overview of iCloud Key-Value Data Storage

The primary purpose of iCloud Key-Value data storage is to allow small amounts of data to be shared between instances of applications running on different devices, or even different applications on the same device. The data may be synchronized as long as it is encapsulated in either an NSString, NSDate, NSArray, NSData, Boolean, NSDictionary or NSNumber object.

iCloud data synchronization is achieved using the NSUbiquitousKeyValueStore class introduced as part of the iOS 5 SDK. Values are saved with a corresponding key using the setter method corresponding to the data type, the format for which is set<datatype>: where <datatype> is replaced by the type of data to be stored (e.g. the setString: method is used to save an NSString value). For example, the following code fragment creates an instance of an NSUbiquitousKeyValueStore object and then saves a string value using the key “MyString”:

NSUbiquitousKeyValueStore *keyStore = 
     [[NSUbiquitousKeyValueStore alloc] init];
[keyStore setString:@”Saved String” forKey:@"MyString"];

Once key-value pairs have been saved locally they will not be synchronized with iCloud storage until a call is made to the synchronize method of the NSUbiquitousKeyValueStore method:

[keyStore synchronize];

It is important to note that a call to the synchronize method does not result in an immediate synchronization of the locally saved data with the iCloud store. iOS will, instead, perform the synchronization at what the Apple documentation refers to as “an appropriate later time”.

A stored value may be retrieved by a call to the appropriate method corresponding to the data type to be retrieved (the format of which is <datatype>forKey:) and passing through the key as an argument. For example, the stored string in the above example may be retrieved as follows:

NSString *storedString = [keyStore stringForKey:@"MyString"];

Sharing Data Between Applications

As with iCloud document storage, key-value data storage requires the implementation of appropriate iCloud entitlements. In this case the application must have the com.apple.developer.ubiquity-kvstore-identifier entitlement key configured in the project’s entitlements file. The value assigned to this key is used to identify which applications are able to share access to the same iCloud stored key-value data.

If, for example, the ubiquity-kvstore-identifier entitlement key for an application named MyApp is assigned a value of ABCDE12345.com.mycompany.MyApp (where ABCDEF12345 is developer’s unique team or individual ID) then any other applications using the same entitlement value will also be able to access the same stored key-value data. This, by definition, will be any instance of the MyApp running on multiple devices, but applies equally to entirely different applications (for example MyOtherApp) if they also use the same entitlement value.


Data Storage Restrictions

iCloud key-value data storage is provided to meet the narrow requirement of performing essential synchronization between application instances, and the data storage limitations imposed by Apple clearly reflect this.

The amount of data that can be stored per key-value pair is 64Kb. The per-application key-value storage limit is 256 individual keys which, combined, must also not exceed 64Kb in total.

Conflict Resolution

In the event that two application instances make changes to the same key-value pair, the most recent change is given precedence.

Receiving Notification of Key-Value Changes

An application may register to be notified when stored values are changed by another application instance. This is achieved by setting up an observer on the NSUbiquitousKeyValue-StoreDidChangeExternallyNotification notification. This notification is triggered when a change is made to any key-value pair in a specified key value store and is passed an array of strings containing the keys that were changed together with an NSNumber indicating the reason for the change. In the event that the available space for the key-value storage has been exceeded this number will match the NSUbiquitousKeyValueStoreQuotaViolationChange constant value.

An iCloud Key-Value Data Storage Example

The remainder of this chapter is devoted to the creation of an application that uses iCloud key-value storage to store a key with a string value using iCloud. In addition to storing a key-value pair, the application will also configure an observer to receive notification when the value is changed by another application instance.

Begin the application creation process by launching Xcode and creating a new Single View Application project with the name and class prefix of iCloudKeys.

Enabling the Application for iCloud Key Value Data Storage

A mandatory step in the development of the application is to configure the appropriate iCloud entitlement. This is achieved by selecting the application target at the top of the Xcode project navigator panel and selecting the Summary tab in the main panel. Scroll down the summary information until the entitlements section comes into view and turn on the Enable Entitlements option:


Enabling iCloud entitlements in Xcode

Figure 29-1


Once selected, Xcode will create an entitlements file for the project named iCloudKeys.entitlements containing the appropriate iCloud entitlements key-value pairs. Select the entitlements file from the project navigator and note the value assigned to the ubiquity-kvstore-identity key. By default this is typically comprised of your team or individual developer ID combined with your reverse company domain URL and application ID. Any other applications that use the same value for the entitlement key will share access to the same iCloud based key-value data stored by this application.

Implementing the View Controller

The application is going to consist of a text field into which a string may be entered by the user and a button which, when selected, will save the string to the application’s iCloud key-value data store. As such, the application will need an outlet to the text field and method to be called when the button is selected. In addition, an instance of the NSUbiquitousKeyStore class will be needed. Choose the iCloudKeysViewController.h file, therefore, and modify it as follows:

#import <UIKit/UIKit.h>

@interface iCloudKeysViewController : UIViewController {
    UITextField *textField;
    NSUbiquitousKeyValueStore *keyStore;
}
@property (strong, nonatomic) IBOutlet UITextField *textField;
-(IBAction)saveKey;
@end

Modifying the viewDidLoad Method

Having declared the outlets and action for the user interface and created a variable to point to the NSUbiquitousKeyValueStore object the next step is to modify the viewDidLoad method of the view controller. Select the iCloudKeysViewController.m implementation file and modify it to add the @synthesize directive for the textField outlet. Locate the viewDidLoad method and modify it so that it reads as follows:

#import "iCloudKeysViewController.h"

@implementation iCloudKeysViewController
@synthesize textField;
.
.
.
- (void)viewDidLoad
{
    [super viewDidLoad];
    keyStore = [[NSUbiquitousKeyValueStore alloc] init];

    NSString *storedString = [keyStore stringForKey:@"MyString"];

    if (storedString != nil){
        textField.text = storedString;
    }

    [[NSNotificationCenter defaultCenter] addObserver:self
      selector: @selector(ubiquitousKeyValueStoreDidChange:)
      name: NSUbiquitousKeyValueStoreDidChangeExternallyNotification
      object:keyStore];
}

The method begins by allocating and initializing an instance of the NSUbiquitousKeyValueStore class and assigning it to the keyStore variable previously declared in the iCloudKeysViewController.h file. Next, the stringForKey method of the keyStore object is called to check if the MyString key is already in the key-value store. If the key exists the string value is assigned to the text property of the text field object via the textField outlet.

Finally, the method sets up an observer to call the ubiquitousKeyValueStoreDidChange: method when the stored key value is changed by another application instance.

Having implemented the code in the viewDidLoad method the next step is to write the ubiquitousKeyValueStoreDidChange: method.

Implementing the Notification Method

Within the context of this example application the ubiquitousKeyValueStoreDidChange: method, which is triggered when another application instance modifies an iCloud stored key-value pair, is provided to notify the user of the change via an alert message and to update the text in the text field with the new string value. The code for this method, which needs to be added to the iCloudKeysViewController.m file is as follows:

-(void) ubiquitousKeyValueStoreDidChange: (NSNotification *)notification
{
    UIAlertView *alert = [[UIAlertView alloc]
                  initWithTitle:@"Change detected"
                  message:@"iCloud key-value store change detected"
                  delegate:nil
                  cancelButtonTitle:@"Ok"
                  otherButtonTitles:nil, nil];
    [alert show];
    textField.text = [keyStore stringForKey:@"MyString"];
}

Implementing the saveData Method

The final coding task prior to designing the user interface involves implementation of the saveData: action method. This method will be called when the user touches the button in the user interface and needs to be implemented in the iCloudKeysViewController.m file:

-(void)saveKey
{
    [keyStore setString:textField.text forKey:@"MyString"];
    [keyStore synchronize];
}

The code for this method is quite simple. The setString method of the keyStore object is called, assigning the current text property of the user interface textField object to the “MyString” key. The synchronize method of the keyStrore object this then called to ensure that the key-value pair is synchronized with the iCloud store.

Designing the User Interface

The user interface for the application simply needs a text field and a button. Select the iCloudViewController.xib file, display the object library (View -> Utilities -> Show Object Library) and drag and drop the two objects into the view canvas. Double click on the button object and change the text to Store Key. The completed view should resemble Figure 29-2:


The user interface for an example iOS 5 iPhone iCloud key-value application

Figure 29-2


Ctrl-click on the File’s Owner entry, drag the resulting line to the text field object and release before selecting the textField outlet from the resulting menu. Ctrl-click on the Store Key button, drag the line to the File’s Owner and select the saveKey menu option to establish the connection to the action method.

Testing the Application

In order to adequately test the application it must first be installed on a physical device since iCloud functionality cannot be tested using the iOS Simulator. For details on installing applications on a device refer to the chapter entitled Testing iOS 5 Apps on the iPhone – Developer Certificates and Provisioning Profiles. Once the application is installed and running on the device, enter some text into the text field and touch the Store Key button. Stop the application from running by clicking on the Stop button in the Xcode toolbar then re-launch by clicking Run. When the application reloads, the text field should be primed with the saved value string.

In order to test the change notification functionality install the application on a second device, and with the application running on both devices change the string on one device and save the key. After a short delay the second device will detect the change, display the alert and update the text field to the new value.

In the absence of a second device, simply create an identical second application with a different name but the same entitlement key value and install it on the same device. Launch the first application and leave it running the in background on the device. Launch the second application, change the value in the text field and click the Store Key button. Return the first application to the foreground and wait for the alert to appear:


The example iPhone iOS 5 iCloud key-value storage app running

Figure 29-3


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
Using iCloud Storage in an iOS 5 iPhone ApplicationiOS 5 iPhone Data Persistence using Archiving