8

I'm struggling a bit with the idea of iCloud and posted a more general question here. My biggest problem is to decide whether I should stop putting the user's data in the good old documents folder which is found in the app's sandbox. To illustrate my problem:

enter image description here

The docs don't give an answer as far as I can see. Let's suppose I have an App which handles different txt files. Once I start my app, I simply check if any txt files are in the cloud like so:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSLog(@"AppDelegate: app did finish launching");
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];

    // (1) iCloud: init

    NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
    if (ubiq) {
        NSLog(@"User has iCloud enabled! Let's get the txt files from the cloud.");
        [self loadDocument];
    } else {
        NSLog(@"User doesn't have iCloud enabled. App is thus worthless.");
    }


    return YES;
}

I then have a method to check if there are any txt files in the cloud and if so, load them. If not, I simply create new txt files in the cloud.

This means that the app does not store any data in the documents folder. As far as I understand it, everything is either in the local iCloud storage of my device (which is also accessible if the user is OFFLINE) or in the cloud. So the text file exists in two places: on my device and the cloud.

So there is simply no need to store a third copy in my local documents folder, right? Or is this essential for some reason I have overlooked? In other words, for what should I use the local documents folder if I offer iCloud to my users? (And can I simply ignore those who won't sign up for iCloud?)


EDIT: Just to clarify, when I'm talking about the standard documents folder in the app's sandbox, I mean this one:

NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
Community
  • 1
  • 1
n.evermind
  • 11,944
  • 19
  • 78
  • 122
  • For what it's worth; iCloud will [backup](http://www.marco.org/2011/10/13/ios5-caches-cleaning) the Document directory if the user has backup enabled. – vcsjones Oct 17 '11 at 19:36
  • 1
    Another FWIW: I wouldn't ignore users who don't have iCloud enabled. Most of the Apple dev docs talk about being able to migrate data into iCloud and out when the user enables/disables for your app. – Ben Zotto Oct 17 '11 at 20:04
  • @quixoto: I see what you mean, but doesn't it feel convoluted to you to have three copies of the same thing floating about? Also, what would be the best way to migrate data? It appears that I would need to do two things at the same time: care about iCloud AND save to my directory. When will I do this? Do I implement this in the UIDocument while data is pushed to the cloud? All of this feels so convoluted as I need to worry about two sets of data which I need to keep in sync all the time. Why would a user not enable iCloud? – n.evermind Oct 17 '11 at 20:18
  • 1
    I definitely would not ignore non-iCloud users. There is no benefit for iCloud document storage if a user only has a single device (storing documents in the iCloud storage is only useful for keeping multiple devices in sync). – Ron Oct 21 '11 at 22:10
  • @Ron Well, even if you only have one device, you use the backup function, i.e. you want your docs (especially if they are small txt files with important information) to be always back-uped to the cloud. – n.evermind Oct 22 '11 at 09:39
  • @n.evermind ... you are right that iCloud can be used for backup, but backing up to iCloud is taken care of by iOS and needs no special attention from your code. If the user wants to back up to iCloud, and if they turn on iCloud back-up in settings, then all of your data in the "documents" directory will be automatically backed up to the cloud without you needing to change a line of code. – Ron Oct 26 '11 at 02:54
  • @Ron also users may run out of space, and they need to disable iCloud for some apps which may include your app. And backup and iCloud is two different things. – Vitim.us Feb 05 '13 at 05:13

3 Answers3

3

Perhaps I'm a bit slow, by re-reading the docs for the 4th or 5th time, I came across this which suggests that you should always create your files in the sandbox and then move them to the cloud. So in a way, Apple suggests to have 3 versions of the same file at all times:

Apps use the same technologies to manage files and directories in iCloud that they do for local files and directories. Files and directories in iCloud are still just files and directories. You can open them, create them, move them, copy them, read and write from them, delete them, or any of the other operations you might want to do. The only differences between local files and directories and iCloud files and directories is the URL you use to access them. Instead of URLs being relative to your app’s sandbox, URLs for iCloud files and directories are relative to the corresponding iCloud container directory.

To move a file or directory to iCloud:

Create the file or directory locally in your app sandbox. While in use, the file or directory must be managed by a file presenter, such as a UIDocument object.

Use the URLForUbiquityContainerIdentifier: method to retrieve a URL for the iCloud container directory in which you want to store the item. Use the container directory URL to build a new URL that specifies the item’s location in iCloud. Call the setUbiquitous:itemAtURL:destinationURL:error: method of NSFileManager to move the item to iCloud. Never call this method from your app’s main thread; doing so could block your main thread for an extended period of time or cause a deadlock with one of your app’s own file presenters. When you move a file or directory to iCloud, the system copies that item out of your app sandbox and into a private local directory so that it can be monitored by the iCloud daemon. Even though the file is no longer in your sandbox, your app still has full access to it. Although a copy of the file remains local to the current device, the file is also sent to iCloud so that it can be distributed to other devices. The iCloud daemon handles all of the work of making sure that the local copies are the same. So from the perspective of your app, the file just is in iCloud.

All changes you make to a file or directory in iCloud must be made using a file coordinator object. These changes include moving, deleting, copying, or renaming the item. The file coordinator ensures that the iCloud daemon does not change the file or directory at the same time and ensures that other interested parties are notified of the changes you make.

See here.

n.evermind
  • 11,944
  • 19
  • 78
  • 122
2

There is no reason to store documents both in local storage as well as in iCloud. However, you should give users the option of turning iCloud storage off. With iCloud storage off, you should only look for files in local storage (as with pre-iOS5 apps). The best thing is to try to isolate the part of your code that needs to know where documents are stored, and have it test whether or not iCloud is available and enabled and have that piece of code return the URL where documents should be stored.

Update: If you want to diverge for iOS5 vs. iOS4, you just need to test if the iOS5 features are there. There are several ways that you can do this. One way is to check:

if ([UIDocument class] == nil)

On iOS4 this will be true, and on iOS5 this will be false. I don't know what kind of datastructures you have for your files, but one thing you could do is create a wrapper around UIDocument. Inside this wrapper class, you could have instance variables for a UIDocument structure as well as for fields you would need in IOS4 (such as the path to the file). When you instantiate your class, test whether iCloud is enabled and if UIDocument is available, and if so, use it and set the field. Otherwise, set the other fields and leave the UIDocument field to be nil. When you need to do operations on your "file", test if the UIDocument field is nil, and if it is do it the "old" way. Otherwise, just pass on the request to the UIDocument object.

Ron
  • 1,305
  • 2
  • 14
  • 22
  • Thanks. Do you have any sample code? My biggest problem is when to use UIDocument and if I should combine that with the old method of writing to my sandbox. So, for example, I check if there are docs in the cloud or the local docs directory (if cloud turned off). What if I want to write? Do first call the UIDocument procedures and then the old procedures to write to my local directory (if cloud turned off)? I (as a beginner) just feel that this completely clutters my code and I only want to support iOS 5 devices, why bother about the old ways? As for users with a single device, see above. – n.evermind Oct 22 '11 at 09:38
  • See the above for more details. – Ron Oct 26 '11 at 03:02
  • 1
    As a rule, you never check for a class you know to be available in a certain iOS version, you check against the capability. `NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]; if (ubiq) { NSLog(@"iCloud access at %@", ubiq); // TODO: Load document... } else { NSLog(@"No iCloud access"); }` (Code lifted from (http://stackoverflow.com/questions/8957036/simple-icloud-implementation) – smilespray Aug 27 '12 at 21:59
1

Remember that if the user has enabled device backup to iCloud, the documents directory gets backed up anyways.

It really depends on if your planning to use iCloud as a sync tool between apps / platforms. If your not, it really doesn't make sense to use iCloud to store your documents.

cocoahero
  • 1,302
  • 9
  • 12
  • So in other words, if I want to build an app which syncs the stuff you create, you only store stuff in the cloud, right? There is no need to the document directory anymore? – n.evermind Oct 17 '11 at 19:41
  • 1
    If iCloud does caching behind the scenes (which I believe it does) you are correct. – cocoahero Oct 17 '11 at 19:45
  • Thanks, but it feels strange to give up the good old documents directory entirely. So if people don't use iCloud, they won't be able to use the app... which is fine, I suppose. I'm just a bit scared to put everything in the cloud... – n.evermind Oct 17 '11 at 19:48
  • 1
    This doesn't answer the OP's question. He's asking about full iCloud-based document management, not backup. – Ben Zotto Oct 17 '11 at 19:54