Professional Documents
Culture Documents
Table of Contents
Introduction ........................................................................................................... 3
How iCloud Works ................................................................................................. 4
Configuring iCloud in iOS ....................................................................................... 8
Enabling iCloud in your App ................................................................................... 9
Checking for iCloud Availability ............................................................................ 15
iCloud API Overview............................................................................................. 17
Opening an iCloud File ......................................................................................... 18
Conclusion ........................................................................................................... 26
www.andolasoft.com
Introduction
iCloud is a service that helps users synchronize their data across devices. It is a set
of central servers which stores documents, and makes the latest version available
to every device/app compatible with iCloud (iPhone, iPod, iPad, Mac, or even
Windows PC).
Here, well look into iCloud by implementing a set of simple applications which
interact with cloud servers to read, write & edit documents. In the process, well
learn about the new UI Document class, querying iCloud for files, auto-saving and
so much more!
To get the most out of this session, we recommend you to have two iOS devices
(iPhone/iPad) ready with you.
For cases when it truly is a problem, it allows you fine-grained control over how to
handle the problem as a developer (also you can always ask users what they
would like to do).
2. Background Management: iOS apps only have limited access to running tasks
in the background, but keeping your documents up-to-date is something you
always want to do.
pushed to the cloud, and iCloud uses this info to determine what needs to be
pulled to each device.
Note that the devices pull data from the cloud only when it's appropriate; Which
means it depends on the OS and platform. For example if an iPhone has much less
power and battery dependency than an iMac, the iOS might decide to notify
just the presence of a new file, without downloading it. Whereas Mac OS X might
start the download immediately after the notification.
The important aspect is that an app is always aware of the existence of a new file,
or changes to an already existing file. Also, through an API the developer is free to
implement the synchronization policy. The API allows an app to know the
situation on iCloud even if the files are not yet local, leaving the developer free
to choose whether (and when) to download an updated version.
Continued.
Once youre sure iCloud is working fine, lets try it out in an app developed by
you.
In this session, well be creating a simple app that manages a shared iCloud
document called dox. The app will be universal and will be able to run on both
iPhone and iPad, so we can see changes made on one device propagated to the
other.
There are three steps in this, so lets try them out.
1. Create an iCloud-enabled App ID
To do this, visit the iOS Developer Center and log onto the iOS Provisioning Portal.
Create a new App ID for your app similar to the following screenshot:
10
Note: Be sure to end your App ID with dox in this session, because that is what
we are naming the project. For example, you could enter com.yourname.dox.
After you create the App ID, you will see that Push Notifications and Game Center
are automatically enabled, but iCloud requires you to manually enable it. Click the
Configure button to continue.
On the next screen, click the checkbox next to Enable for iCloud and click OK
when the popup appears. If all works well, you will see a green icon next to the
word Enabled. Then just click Done to finish.
11
After creating a profile, refresh the page until it is ready for download and then
download it to your machine. Once its downloaded, double click on it to bring it
into Xcode, and verify if it's visible in Xcodes Organizer.
12
After youve finished creating the project, select your project in the Project
Navigator and select the dox target. Select the Summary tab, and scroll all the
way down to the Entitlements section.
Once youre there, click the Enable Entitlements checkbox, and it will autopopulate the other fields based on your App ID, as shown below:
13
}
Here we use a new method called URLForUbiquityContainerIdentifier. This
method allows you to pass in a container identifier (like we had set up earlier in
the iCloud Containers section) and it'll return you a URL to access the files in
iCloud storage.
You need to call this on startup for every container you want to access, to give
your app the permission to access the URL. If you pass nil to the method (like we
do here), it automatically returns the first iCloud Container set up for the project.
Since we only have one container, this makes it nice and easy.
Compile and run your project (on a device, because iCloud does not work on the
simulator) and if everything goes well, you should see a message in your console
like this:
iCloud access at file://localhost/private/var/mobile/Library/Mobile%20
Documents/KFCNEC27GU~com~razeware~dox/
Note that the URL it returns is actually local on the system! This is because the
iCloud daemon transfers files from the central servers to a local directory in the
device, on your behalf. Your application can then retrieve files from this directory
or send updated versions and the iCloud daemon will synchronize everything for
you.
This directory is outside of your app, but as mentioned above the act of calling
URLForUbiquityContainerIdentifier gives your app the permission to access this
directory.
16
To store documents in iCloud you can do things manually if youd wish, by moving
files to/from the iCloud directory with new methods in NSFileManager and the
new classes NSFilePresenter, NSFileCoordinator.
However doing this is fairly complex and unnecessary in most cases, because iOS
has introduced a new class to make working with iCloud documents a lot easier.
Continued.
17
#define kFILENAME
@"mydocument.dox"
Next, lets extend the application delegate to keep track of our document, and a
metadata query to look up the document in iCloud. Modify AppDelegate.h to look
like the following:
#import <UIKit/UIKit.h>
#import "Note.h"
@class ViewController;
@interface AppDelegate : UIResponder
<UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) ViewController
*viewController;
@property (strong) Note * doc;
@property (strong) NSMetadataQuery *query;
- (void)loadDocument;
@end
Then switch to AppDelegate.m and synthesize the new properties:
@synthesize doc = _doc;
@synthesize query =
_query;
18
- (void)loadDocument {
NSMetadataQuery *query = [[NSMetadataQuery alloc]
init];
_query = query;
}
Note that before we can load a document from iCloud, we first have to check
whats in it. We cant simply enumerate the local directory returned to us by
URLForUbiquityContainerIdentifier, because there may be files in iCloud not yet
pulled down locally.
If you ever worked with Spotlight on the Mac, youll be familiar with the class
NSMetadataQuery. It is a class to represent results of a query related to the
properties of an object, such as a file.
19
In building such a query you have the possibility to specify parameters and scope,
i.e. what you are looking for and where. In the case of iCloud files the scope is
always NSMetadataQueryUbiquitousDocumentsScope. You can have multiple
scopes, so we have to build an array containing just one item.
So continue loadDocument as follows:
- (void)loadDocument {
NSMetadataQuery *query = [[NSMetadataQuery alloc]
init];
_query = query;
[query setSearchScopes:[NSArray arrayWithObject:
NSMetadataQueryUbiquitousDocumentsScope]];
}
Now you can provide the parameters for the query. If you ever worked with
CoreData or even arrays you probably are familiar with the approach. Basically,
you build a predicate and set it as parameter of a query/search.
In our case we are looking for a file with a particular name, so the keyword should
be NSMetadataItemFSNameKey, where FS stands for file system. Add the code
to create and set the predicate next:
- (void)loadDocument {
NSMetadataQuery *query = [[NSMetadataQuery alloc]
init];
_query = query;
[query setSearchScopes:[NSArray arrayWithObject:
NSMetadataQueryUbiquitousDocumentsScope]];
NSPredicate *pred = [NSPredicate
predicateWithFormat:
@"%K == %@", NSMetadataItemFSNameKey,
kFILENAME];
[query setPredicate:pred];
20
}
You might not have seen the %K substitution before. It turns out predicates treat
formatting characters a bit differently than you might be used to, with NSStrings
stringWithFormat. When you use %@ in predicates, it wraps the value you
provide in quotes. You dont want this for keypaths, so you use %K instead to
avoid wrapping it in quotes. For more information, see the Predicate Format
String Syntax in Apples documentation.
Now the query is ready to be run, but since it is an asynchronous process we need
to set up an observer to catch a notification when it's completed.
The specific notification we are interested in has a pretty long (but descriptive)
name: NSMetadataQueryDidFinishGatheringNotification. It's posted when the
query has finished gathering info from iCloud.
So here is the final implementation of our method:
- (void)loadDocument {
NSMetadataQuery *query = [[NSMetadataQuery alloc]
init];
_query = query;
[query setSearchScopes:[NSArray arrayWithObject:
NSMetadataQueryUbiquitousDocumentsScope]];
NSPredicate *pred = [NSPredicate
predicateWithFormat:
@"%K == %@", NSMetadataItemFSNameKey,
kFILENAME];
[query setPredicate:pred];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(queryDidFinishGathering:)
21
name:NSMetadataQueryDidFinishGatheringNotification
object:query];
[query startQuery];
}
Now that this is in place, add code for the method that will be called when query
is completed:
- (void)queryDidFinishGathering:(NSNotification
*)notification {
NSMetadataQuery *query = [notification object];
[query disableUpdates];
[query stopQuery];
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:NSMetadataQueryDidFinishGatheringNotification
object:query];
_query = nil;
[self loadData:query];
}
Add the starter implementation of this method next (above
queryDidFinishGathering):
- (void)loadData:(NSMetadataQuery *)query {
if ([query resultCount] == 1) {
NSMetadataItem *item = [query
resultAtIndex:0];
}
}
22
NSMetadataItemURLKey
NSMetadataItemFSNameKey
NSMetadataItemDisplayNameKey
NSMetadataItemIsUbiquitousKey
NSMetadataUbiquitousItemHasUnresolvedConflictsKey
NSMetadataUbiquitousItemIsDownloadedKey
NSMetadataUbiquitousItemIsDownloadingKey
NSMetadataUbiquitousItemIsUploadedKey
NSMetadataUbiquitousItemIsUploadingKey
NSMetadataUbiquitousItemPercentDownloadedKey
NSMetadataUbiquitousItemPercentUploadedKey
}
}
When you create a UIDocument (or a subclass of UIDocument like Note), you
always have to use the initWithFileURL initializer and give it the URL of the
document to open. We call it here, by passing the URL of the located file and
store it away in an instance variable.
Now we are ready to open the note. As explained previously you can open a
document with the openWithCompletionHandler method. So continue loadData
as follows:
- (void)loadData:(NSMetadataQuery *)query {
if ([query resultCount] == 1) {
NSMetadataItem *item = [query resultAtIndex:0];
NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
Note *doc = [[Note alloc] initWithFileURL:url];
self.doc = doc;
[self.doc openWithCompletionHandler:^(BOOL success) {
if (success) {
NSLog(@"iCloud document opened");
} else {
NSLog(@"failed opening document from iCloud");
}
}];
}
}
When you run the app now, it'll work except it'll never print out either of the
above messages! This is because there is currently no document in our container
in iCloud, so the search isnt finding anything (and the result count is 0).
24
Since the only way to add a document on the iCloud is via an app, we need to
write some codes to create a doc. We will append this to the loadData method
that we defined earlier. When the query returns zero results, we should:
You can even try this on another device and you should see the iCompileloud
document opened message show up on the second device (because the
document already exists on iCloud now!)
Now iCloud integration in your application is complete.
Source-raywenderlich.com
Conclusion
Cloud is the way forward. Hence, integrating Cloud is no more a choice for an App
Developer. And, what better than Apple's highly popular iCloud?
We would be more than happy to hear your feedback/suggestions on
info@andolasoft.com.
------------------------------------------------------------------------------------------------------------------------------------------
Andolasoft builds high performance iOS Apps assuring seamless integration (With More than
300+ Apps deployed to the App Store). If you have anything to discuss, get in touch with
Andolasoft's iOS Experts.
www.andolasoft.com
26