Chapter 25: Data in the Cloud

With iOS 5 (and Mac OS X Lion), Apple introduced a new and very important feature, or service, called iCloud. iCloud stores content and continuously pushes it to all devices associated with a specific Apple account. To the end user, the integration is seamless and happens automatically. However, to give your customers that kind of user experience, you need to do some challenging development.

Prior to iCloud, developers implemented Dropbox Sync to synchronize data across user devices. Although this approach handled the problem of syncing data in the iOS 4 era, it’s limited to flat files, and more important, users needed to have a Dropbox account and needed to sign in with their Dropbox credentials on your app. With iCloud, no such explicit signing-in is necessary. You get automatic access to the iCloud data store you declare for your app without extra action on the part of the user. Moreover, iCloud has support for key-value data storage and excellent support for Core Data-managed apps.

Recently, many companies have begun rolling out backend as a service (BaaS). Parse, StackMob, Kinvey, CloudRec, and Applicasa are just a few of these services. Two of them, StackMob and Parse, are becoming increasingly popular among developers, which means that their longevity as companies will be much higher than others.

In this chapter, I briefly explain iCloud, Parse, and StackMob. Parse and StackMob have important advantages (and a differentiator) over iCloud. First, they have a REST API, which you can use to access your data from a web-based application. Second, they have an Android, a Windows Phone 7, and an HTML 5 SDK. If your product requires an Android client or an HTML 5 client, using a third-party service rather than iCloud may be beneficial.

Having said all that, it’s time to get started.

iCloud

iCloud allows you to store two kinds of data on iCloud: traditional files (document file storage) and key-value data. If your app currently uses NSUserDefaults to store app-specific settings, consider using iCloud key-value data storage to sync those settings across the users’ devices.

The preferred way to store documents on iCloud is to design your persistent models as subclasses of UIDocument or UIManagedDocument. UIDocument is for storing document-based content, whereas UIManagedDocument is for storing database-related content. The next sections discuss the differences between them.

UIDocument

Using UIDocument is not an iCloud prerequisite; however, if you manage individual files, you also need to manage file presenters and coordinators to support iCloud’s locking mechanism. UIDocument has built-in support for this mechanism. Additionally, it helps to resolve version conflicts created by updates on other devices.

Another important feature provided by UIDocument is its excellent support for managing file packages. (A file package is a directory of files that appears to the user as a single file. On the Mac, applications in your /Applications folder are file packages.) File packages can store individual components in your app as separate files, so a change to one of those components means that only the changed file needs to be sent to iCloud. For example, in a drawing app, you may consider saving the actual drawing in one file and save sets of custom brushes and fonts in separate files within the same file package. You can still manage the entire file package using just one UIDocument subclass. Now, when a user opens a large drawing and edits a custom brush, only the file representing the custom brush needs to be sent, which is usually much smaller than the drawing.

UIManagedDocument

UIManagedDocument is a concrete subclass of UIDocument that integrates with Core Data. You initialize it with the URL of your persistent store, and the document object does the rest. It then creates a Core Data stack based on your Core Data model file (.xcdatamodeld file). If you’re currently using Core Data to store your user content, you should adopt UIManagedDocument in your app to support iCloud data syncing. This is the easiest way to migrate apps that currently use Core Data.

Key-Value Data Storage

The second type of data you can store is key-value data. If your app currently stores app-specific settings in NSUserDefaults, consider using iCloud’s key-value data storage to sync these settings across users’ devices. The total size of data you store here cannot exceed 64K and no key can be more than 4K. In most cases, you’ll be saving a Boolean or an integer or a string, which usually is less than 4K. If you’re storing serialized models, however, ensure that they’re less than 4K, or use UIDocument as discussed in the previous section.

Understanding the iCloud Data Store

To start using iCloud in your app, you first need to configure your App ID for iCloud usage. After doing so, generate your provisioning profile and request entitlements in your app. Depending on the data storage requirements in your app, you need to request either one or both of the following entitlements.

iCloud Entitlements Key

com.apple.developer.ubiquity-container-identifiers

com.apple.developer.ubiquity-kvstore-identifier

The first one is for document storage, and the second one is for key-value storage. Once this is done, you can start moving documents from your application’s sandbox to iCloud storage. The entitlements ensure that data generated by your app is sandboxed and will not be accessible to other apps.

Sharing Data Within Apps (or App Suites)

On iCloud, you identify and request a data store container by its unique ID. This is normally your application’s App ID, but not necessarily. You can use the same iCloud data store container for two of your apps and share data within them. This feature is very powerful, especially if you’re developing lite and pro versions of an app. You can now use the same ubiquitous container identifier, which means that data created by a user using the lite version becomes automatically available if he purchases your pro version, making the migration process easier. You can also use this technique to share data among a suite of apps you build.

The iCloud data store resides on the user’s iPhone until it’s moved to iCloud by the iCloud daemon running on the iOS device. Once you move the document to iCloud storage, you can safely delete the original copy because all subsequent edits will happen directly to the file stored on iCloud. As a developer, you don’t have to worry about uploading to a remote source or be bothered about network disconnection. The iCloud daemon automatically takes care of this syncing. You should, however, handle conflict resolutions. The default conflict resolution strategy iCloud follows is to choose the last modified document. Although this might be okay in some cases, you should evaluate this strategy on a case-by-case basis for your app.

Storing Data Within Your iCloud Container

Starting from iOS 5 and later, the Settings app on every device has an iCloud section that allows users to see how much data they’ve used on iCloud for backup and how much data has been used by apps syncing with iCloud. When you store your files in the iCloud container, they appear as a big blob of data to the user. When you store them in the Documents directory, users can see the individual files and their sizes. Files in the Documents directory can be deleted one by one, whereas data stored outside this directory appears as a big blob and must all be deleted at the same time. To avoid confusion and to play nice, always store any user-generated files in the Documents directory and store miscellaneous metadata that you don’t want the users to see outside this directory.

A Word About iCloud Backup

With versions of iOS prior to iOS 5, when the device syncs with iTunes, the contents of your app’s Documents folder are automatically backed up. With iOS 5 and later devices, the same contents are backed up to the iCloud, with one exception: Documents you store on iCloud manually are not included in this backup (because they’re already on iCloud). Do note that this automatic backup is different than iCloud syncing. Backed-up documents are treated as opaque data that can be used only to completely restore an iOS device. Individual file access is not possible programmatically or by the user.

Disadvantages

Although iCloud offers seamless syncing of user data and easy conflict management, no REST API is available for accessing the data stored by your application. A REST API is important if you want to provide a web frontend to your product. Any software as a service that offers syncing across devices is looking at the possibility of rolling out a web-based application in the near future, and iCloud’s lack of a REST API makes that almost impossible. Although Apple’s own apps (Mail, Contacts, Calendar, Reminders, and Notes) have an impressive web-based frontend, as of iOS 6, there’s no mention of a REST API for iCloud.

The lack of a web interface for looking at your data makes debugging harder as well. With iCloud, debugging becomes harder, and the only way you will know that the data has been backed up to iCloud is when the second device successfully downloads and displays the data. A longer debugging cycle exponentially increases the product’s development time.

Third-Party Cloud Offerings

Several third-party offerings help developers move and sync their data on the cloud without worrying about maintaining a server. Parse and StackMob seem to be the choices these days because of their reliability over the last couple of years and the plethora of features they offer, including a REST API, a JavaScript API, and SDKs for competing platforms like Android and Windows Phone.

In addition, almost all third-party offerings have good support for debugging, meaning that data synced from a mobile device is readily available for viewing on a web application. This is something that iCloud lacks, which makes debugging difficult. With iCloud, the only way to know that something has been successfully stored in iCloud is when another device can read (and display) that data.

As I mention earlier, I discuss both Parse and StackMob in this chapter. Both turn out to be reliable alternatives to Apple’s iCloud. I also discuss the disadvantages of these providers later in this chapter (in the “Disadvantages of Backend as a Service” section) to help you make an educated decision about which to use.

Parse

Parse is a third-party service that allows users to create a complete back-end stack on the cloud. Although Parse has a REST API, when you want to interact with it from your iOS app, you can use the iOS SDK instead. The iOS SDK offers the same set of features offered by the REST API, and there’s no reason not to use it.

Getting Started with Parse

Getting started with Parse is almost as easy as getting started with iCloud, minus the provisioning- and entitlement certificates-generation nightmare. Instead, when you use Parse (or most other equivalent competing services), after logging in to your Parse account, you create an application and use the Application ID and Client Key to authenticate your app with Parse’s backend.

The Application ID/Client Key combo is almost synonymous to the ubiquitous container identifiers you use for iCloud. After you create your app on Parse, you should see a screen similar to the one shown in Figure 25-1.

After you create the application, download the iOS SDK and drag Parse.Framework to your application. Add the dependent frameworks and import the header file, Parse/Parse.h in your AppDelegate.

Copy the Application ID and the Client Key you created for your application and add the following line to the AppDelegate:

[Parse setApplicationId:@”<Your Application ID>” clientKey:@”<Your Client

Key>”];

That completes the setup.

Parse Top Level Objects

The complete Parse framework relies on the following objects: PFObject, PFUser, PFRole, and PFACL. PFObject is like a “God object” that you use throughout your application. It’s almost synonymous with UIManagedObject in iCloud. One important difference, however, is that when you use Parse, there’s almost no support for model versioning, and in fact, there’s no versioned structure for your models. PFObject is like a tableless nosql-style object where you store elements using a key-value pair. In fact, from your app, you create a PFObject for every object that you want to store on the cloud. The other two objects, PFRole and PFUser, are subclasses of PFObject. You’ll be using PFRole and PFUser in your app, if you provide a user account and want to store associated data with a user and want to control access to the data based on the logged in user. Although implementing roles is not hard using iCloud’s UIManagedObject, Parse provides it free and ready for use right out of the box.

9781118449974-fg2501.tif

Figure 25-1 Screenshot of Parse showing the Application ID/Client Key and your data browser

Code

Now that I’ve introduced you to the basics, it’s time to dirty your hands with some code. The main classes you’ll be using are PFObject, PFUser, PFACL, and PFRole.

Storing Objects

Almost everything that you save to cloud using Parse is done through the PFObject. You create a PFObject with a specific class name, add the necessary data as a key-value pair (think NSMutableDictionary), and call the save method. Here’s an example.

Creating and Saving an Object to the Cloud Using Parse

PFObject *object = [PFObject objectWithClassName:@”UserProfile”];

[object setValue:@”Mugunth” forKey:@”userName”];

[object setValue:@”mugunthkumar” forKey:@”twitter”];

[object setValue:@”imk.sg” forKey:@”skype”];

[object setValue:@”blog.mugunthkumar.com” forKey:@”blog”];

[object saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {

  

  if(!succeeded) {

    NSLog(@”%@”, error);

  }

}];

With very few changes, you can link the same UserProfile object with a user account (PFUser). This means only that the logged in user can read/modify the object. Again, Parse allows full access control to developers using the access control object PFACL. Now, take a look at these two objects in action.

  [PFUser logInWithUsernameInBackground:@”mugunth” password:@”magic”

   block:^(PFUser *user, NSError *error) {

    

    if(!user) {

      NSLog(@”%@”, error);

      return;

    }

    PFACL *acl = [PFACL ACLWithUser:user];

    PFObject *object = [PFObject objectWithClassName:@”UserProfile”];

    [object setACL:acl];

    

    [object setValue:@”Mugunth” forKey:@”userName”];

    [object setValue:@”mugunthkumar” forKey:@”twitter”];

    [object setValue:@”imk.sg” forKey:@”skype”];

    [object setValue:@”blog.mugunthkumar.com” forKey:@”blog”];

    

    [object saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {

      

      if(!succeeded) {

        NSLog(@”%@”, error);

      }

    }];    

  }];

The code remains the same except for the initial block that logs a user in and creates an access control list object. When you run the preceding code, you should see the objects when you open the Data Browser on Parse, as shown in Figure 25-2.

9781118449974-fg2502.tif

Figure 25-2 Data browser showing your objects

Retrieving Objects

Retrieving objects from the cloud can’t be easier than this. You use the PFQuery object to get objects from the cloud.

Retrieving Objects from Parse Using PFQuery

  PFQuery *query = [PFQuery queryWithClassName:@”UserProfile”];

  [query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError

   *error) {

    

    NSLog(@”%@”, object);

  }];

When you execute the following code, you’ll see the saved user profile object. You can even filter objects by applying a filter to the PFQuery object.

[query whereKey:@”twitter” equalTo:@”mugunthkumar”];

Offline Mode

What makes Parse powerful is the ability it gives you to work and save objects offline. The Parse framework automatically takes care of synchronizing changes to the cloud when the device comes back online.

All you need to do is call the saveEventually method instead of saveInBackgroundWithBlock:.

With all these features, the most heavy-duty task is writing code to convert objects that must be saved to the cloud to a PFObject. You can do this manually, by writing a method saveToParse in all the models. Another much cleaner and elegant way is to piggyback on Objective-C’s runtime methods. The MKFoundation library has a runtime method that converts your objects to PFObjects, piggybacking on Objective-C’s powerful runtime methods.

MKFoundation is a library available on GitHub that allows you to convert any object in your application to a PFObject. MKFoundation uses Objective-C runtime methods to inspect your objects and creates a PFObject. With small changes the PFObject, such as changing the user/role, you can instantly bring Parse back-end support to your application.

For more in-depth information about Objective-C runtime, read Chapter 28 of this book.

StackMob

StackMob is an alternative to Parse. Although slightly more complicated to use and understand than Parse, the additional complexities come from the fact that it has many more features that might be useful to your application.

Setting Up StackMob

The procedures for setting up StackMob are similar to those for any other third-party framework. Unlike Parse, Stackmob provides the source code for the iOS SDK. You download the sample code and add the source code files directly into your app. As of this writing, the StackMob code base is not ARC-ready, so you have to add –fno-objc-arc to all of the StackMob files.

Again, instead of following the complicated provisioning and certificate entitlements approach, StackMob, like Parse, generates a bunch of API access keys.

Logging In and Uploading and Retrieving Data

Most of StackMob APIs work similar to those in Parse, including logging in and saving and retrieving objects from the cloud. Instead of a PFObject, you create a normal NSDictionary and upload it to StackMob.

A quick look at the code will make things clear.

Storing Data to StackMob

NSMutableDictionary *object = [NSMutableDictionary dictionary];

  [object setValue:@”Mugunth” forKey:@”username”];

  [object setValue:@”mugunthkumar” forKey:@”twitter”];

  [object setValue:@”imk.sg” forKey:@”skype”];

  [object setValue:@”blog.mugunthkumar.com” forKey:@”blog”];

    

//schema name “blogentry” must be 3-25 alphanumeric characters, lowercase

[[StackMob stackmob] post:@”UserProfile”

            withArguments:object andCallback:^(BOOL success, id result){

              if(success){

                //action after successful call

              } else {

                //action after a call results in error

              }

            }];

The preceding code block explains how to save a set of data to the cloud. After you successfully execute this block of code, you’ll see something like Figure 25-3 in your StackMob account.

9781118449974-fg2503.tif

Figure 25-3 StackMob’s Object Datastore browser

The other methods, such as deleting or retrieving data, also operate in a very similar manner to Parse, so I won’t explain them in detail here. However, one thing does set StackMob apart from the competition, which I discuss in the next section.

StackMob Custom Code

The real power and distinguishing feature of StackMob is the capability of supporting custom code/scripts in Java/Scala/Closure. You can write your own custom server-side code and upload it to StackMob and call those APIs from your Mobile App. Why write custom server code when you can do all that on the client? That’s the essence of a backend as a service, right? Although you can write queries, filters, and so on on iOS, you’ll still find that it’s necessary to write back-end code for analytics and data mining. Running complex analytics-related queries from a user’s device is slow. Some startups work on products that depend heavily on data analytics. Without a real back-end server and access to the raw database, it becomes almost impossible to do data analytics from your server. Although a REST API can help, you’re still limited by available Internet bandwidth, whereas custom code running on StackMob servers aren’t.

Disadvantages of Using a Backend as a Service

Both StackMob and Parse are easy for beginners to start with, and both offer out-of-box support for Apple’s Push Notification Services, In App Purchases, friction-free user registration, and Facebook/Twitter support.

The main disadvantage is the dependence of your complete product on a third-party service that, as of 2012, is not yet established (compared to companies like Amazon or Rackspace that provide Infrastructure as a Service). Service disruptions in these back-end providers could potentially bring down your app just as an AWS outage brought down Instagram, Quora, foursquare, and several others at the same time. Although Apple’s iCloud is not immune to this (no company is), think about the risks before considering a third-party solution to replace your backend. There is no silver bullet.

Summary

In this chapter, you read about the different methods available to developers for storing and syncing user data in the cloud. I explained the pros and cons of using iCloud and the pros and cons of using a third-party backend as a service. Moving your data to the cloud should now be easier than you had thought. Knowing about alternatives to iCloud will help you make an educated decision about how to move ahead with your product.

Further Reading

Apple Documentation

The following documents are available in the iOS Developer Library at developer.apple.com or through the Xcode Documentation and API Reference.

iCloud

UIManagedObject Class Reference

WWDC Sessions

WWDC 2012, “Session 209: iCloud Storage Overview”

WWDC 2012, “Session 227: iCloud with Core Data”

WWDC 2012, “Session 237: Advanced iCloud Document Storage”

WWDC 2012, “Session 218: Using iCloud with UIDocument”

WWDC 2012, “Session 224: “Using iCloud with NSDocument”

Other Resources

Parse. “iOS Developer Guide”https://parse.com/docs/ios_guide

StackMob. “StackMob Docs”http://www.stackmob.com/devcenter/

MugunthKumar / MKFoundationhttp://github.com/MugunthKumar/MKFoundation

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.188.27