0
votes

My app uses a single document (UIDocument) to contain its information and never closes it while the app is open. I have implemented iCloud connectivity to save the file so I can share it across devices. When using the simulator (iOS7), I can open the document and save to it. If I quit the App in the simulator, I can still open the iCloud document and work with it when I relaunch.

I'm testing on an iPad (iOS7) and the simulator to work out the updates between devices. I can successfully open the iCloud document (saved by the simulator) and see everything properly on the iPad. However, if I quit the App on the iPad and relaunch it, I get success = NO and Document State = UIDocumentStateSavingError in my openWithCompletionHandler. I captured the error in the handleError method and found this:

Error 
Domain=NSCocoaErrorDomain 
Code=257 "The operation couldn’t be completed. (Cocoa error 257.)" 
UserInfo=0x14650360 {NSFilePath=/private/var/mobile/Library/Mobile Documents/2A9S2V8BH4~com~mishnookasoftware~selists/Lists.archive, NSUnderlyingError=0x1462b590 "The operation couldn’t be completed. Operation not permitted"}

This appears to be a permission denied error. I double checked the certificate to ensure iCloud was enabled for the App, and it is. I have tested to see if changes made on my iPad are pushed to iCloud, by quitting the App in the simulator and relaunching it to see the updates.

I do close the iCloud document in the App Delegate's applicationWillTerminate method ([iCloudListDocument closeWithCompletionHandler:nil];). I'm wondering if the file is not getting properly closed and thus cannot be reopened upon relaunch.

I have searched StackOverflow and could not find anything to help my situation. Any help is greatly appreciated.

1
What happens if you run the iPad first before any document exists in iCloud ? - Duncan Groenewald
Unfortunately, I don't know how to delete the file in iCloud to test that. Also, the app creates the document and starts saving changes to it in iCloud once it starts using iCloud. I'm pretty sure I'd get the same error if I quit the app and relaunch on the iPad. - Greg Walters
Go to the ~Library/Mobile Documents/ directory on your Mac and look for the apps containerId and delete all the contents - Duncan Groenewald
Nope, same problem. When I store locally, the document is read and I can see the data after relaunch. When I store in iCloud, I get the Permission Denied error and the document is not read. - Greg Walters
Add some logging in your close completion handler to see if it is being successfully closed. - Duncan Groenewald

1 Answers

3
votes

Okay, this was strange. I was saving the full path URL to the iCloud document in userDefaults and then reading it and trying to use it to open the iCloud document if I had a valid ubiquityIdentityToken upon relaunch. The full path contained the original URLForUbiquityContainerIdentifier with the document's final location and name appended to it. This action resulted in the document not being found ([[NSFileManager defaultManager] fileExistsAtPath:fileName] = NO, where fileName was taken from the saved full path URL).

Now, the weird part, for me anyway. I had to retrieve the URLForUbiquityContainerIdentifier (NSURL *myUbiquityContainer = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: nil];) again, before I could access the full path URL I had saved. If I did this before I checked if the document existed, [[NSFileManager defaultManager] fileExistsAtPath:fileName] = YES.

Conclusion, upon relaunch of an app wanting to open an existing iCloud document, you must perform both methods:

id currentiCloudToken = [[NSFileManager defaultManager] ubiquityIdentityToken];
NSURL *myUbiquityContainer = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: nil];

This will allow you to access the actual document in the fully qualified path URL, in my case saved from a previous session in the app.