2

Right now in my application I have a top level object with an -(void)archive method that will archive itself to the application's documents directory.

I'm wondering if it's possible to simply save the archive to iCloud rather than locally, by changing the file path.

I've read quite a bit on using iCloud, but I haven't seen this question addressed. I'm guessing it is not possible, but I want to know for sure.

Thank you.

cohenadair
  • 2,072
  • 1
  • 22
  • 38

1 Answers1

2

You shouldn't save a file directly to iCloud but save it locally and then move it to the iCloud folder associated with your app.

First you need to look at file coordination which you should use to save a file to iCloud.

Then you simply retrieve the URL or path for the file you want to save. You get your iCloud directory by calling: [[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:@"myIdentifier"]; Then append the appropriate path components.

Finally you save the file (e.g.myFile.dat) to a temporary local folder like the Application's documents directory and then call: [[NSFileManager defaultManager] setUbiquitous:YES itemAtURL:/*local URL*/ destinationURL:/*Cloud URL*/ error:&error]; This will move the file from the local folder to the iCloud folder and then the OS' syncing daemon does the rest.

If you save into the iCloud documents directory, your file will be visible to the user via iCloud drive. If you save into a different iCloud directory, the user will not be able to see the file.

NOTE: you need to use NSMetadataQuery to discover files saved to iCloud by another device. Also iOS devices do not automatically download files that you save to iCloud; you need to specifically call [[NSFileManager defaultManager] startDownloadingUbiquitousItemAtURL:url error:&error]; to initiate a download. OS X devices will automatically download iCloud files. You can use the NSFilePresenter protocol to watch for changes to your iCloud directory during your app's lifetime (to detect files saved by another device).

Rob Sanders
  • 5,197
  • 3
  • 31
  • 58
  • Good answer! OP should also look into the UIDocument class, which can automate some of these tasks – Jef Jan 06 '15 at 19:48
  • Hmm that doesn't sound too bad. I came across a tutorial that wrapped the top level object in a UIDocument subclass and they handle loading/saving to iCloud in the view controllers, but I feel like it would make more sense to have a method in the top level object that does that so code doesn't have to be copied to each view controller that needs to save to iCloud. My question is this: if I were to do the latter, is it still possible to add a listener to each view controller that will update my top level object if the file on iCloud was changed from another device? – cohenadair Jan 06 '15 at 21:01
  • In terms of code repetition, the way I deal with it is to create a separate class (mine's a singleton) that deals with all saving to and detecting changes in the iCloud folder. Then you can generate your data object from anywhere in your app and pass that though to the singleton for saving and uploading; also this class can post notifications so that different parts of your app can respond to changes in the iCloud folder. As @Jef said, UIDocument will automate many of these tasks for you. I, however prefer this approach for non document based apps. – Rob Sanders Jan 07 '15 at 09:57
  • So when different views are shown how do they know when changes have been made to the iCloud folder? You said your singleton instance responds to changes, so I'm assuming that means once the instance is created it will still respond regardless of the current view? Basically I just want some view controllers to refresh when "myObject" changes, and "myObject" will change when there's changes made to the iCloud folder. – cohenadair Jan 08 '15 at 03:18
  • 1
    Yes so look at [how to make a singleton](http://www.galloway.me.uk/tutorials/singleton-classes/), but the nature of the class design is that it will stick around once it's been instantiated. Then the singleton can be notified of changes to the iCloud folder and pass those notifications to other parts of your app. You shouldn't go round making hundreds of singletons but they are really useful for designating specific jobs and separating code. Good organisation. – Rob Sanders Jan 08 '15 at 17:51
  • I ended up getting it working using UIDocument, a singleton (for saving/loading), and NSMetadataQuery. Thanks a lot for the help! My only issue is my data file is quite large (> 3MB with an archive with 3 images). Is there a way around this? – cohenadair Jan 11 '15 at 23:39
  • Essentially, not really although .dat files as generated by `NSKeyedArchiver` are not best for saving large data. It all depends on the type of thing you're saving. I haven't worked much with images but I know that there a few options for saving when converting to NSData objects. For text you can use .txt or .rtf e.t.c. and for large repetitive data you want to be doing sqlite or some other database format. I suggest you do as much research as possible into the type of data you're saving. – Rob Sanders Jan 13 '15 at 14:07
  • Okay thanks. Because right now the file will get quite large, very fast. – cohenadair Jan 13 '15 at 17:26