2

I can't seem to find any reliable documentation that explains the correct procedure for deleting a UIManagedDocument, and in particular one where the iCloud options have been turned ON.

I understand that this option would delete the file at this fileURL. And this would appear to be fine if iCloud is not being used.

[[NSFileManager defaultManager] removeItemAtURL:fileURL error:&error];

If iCloud is being used then CoreData creates files all over the place, including in /Document/CoreDataUbiquitySupport and in the iCloud /CoreData folder. So in this case is it up to me to call removeUbiquitousContentAndPersistentStoreAtURL for each store in the UIManagedDocument prior to calling [NSFileManager removeItemAtURL]. If so is this documented somewhere ?

[NSPersistentStoreCoordinator removeUbiquitousContentAndPersistentStoreAtURL:storeURL
                                                                     options:@{NSPersistentStoreUbiquitousContentNameKey:fileName,
   NSMigratePersistentStoresAutomaticallyOption:@YES,
         NSInferMappingModelAutomaticallyOption:@YES,
                          NSSQLitePragmasOption:@{ @"journal_mode" : @"DELETE" }}
                                                                       error:&error];
Duncan Groenewald
  • 8,496
  • 6
  • 41
  • 76

2 Answers2

2

Here is my two cents on the issue. I tried what dtrotzjr recommended and didn't have a whole lot of success. It seems that removeUbiquitousContentAndPersistentStoreAtURL:options:error: is great for clearing out data in a UIManagedDocument, but the Logs folder is still there and so are the remnants of the file I'm trying to delete. Here is a simpler method for completely deleting a UIManagedDocument from iCloud or Local Docs:

+ (void)deleteDocumentURL:(NSURL *)url{
    //if we have an iCloud Document, remove it from the UbiquitouseKeyValueStore
    if ([self isiCloudURL:url]) {
        [[NSUbiquitousKeyValueStore defaultStore] removeObjectForKey:[url lastPathComponent]];
    }

    //do the delete on another thread
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
        NSError *coordinationError;

        [coordinator coordinateWritingItemAtURL:url
                                    options:NSFileCoordinatorWritingForDeleting
                                      error:&coordinationError
                                 byAccessor:^(NSURL *newURL) {
         NSError *removeError;
        //code for performing the delete
        [[NSFileManager defaultManager] removeItemAtURL:newURL error:&removeError];

        //if we have an iCloud file...
        if ([self isiCloudURL:url]) {
            //remove log files in CoreData directory in the cloud
            NSURL *changeLogsURL = [[self urlForiCloudLogFiles] URLByAppendingPathComponent:[url lastPathComponent]];
                [[NSFileManager defaultManager] removeItemAtURL:changeLogsURL error:&removeError];
            }
        }];
    });
}

This is pretty much the code from Stanford's CS193 course 2012 + the delete for the changeLogs folder and it works on local and iCloud docs. Please let me know if you see any issues with performing the delete this way.

Paulo Cesar
  • 2,250
  • 1
  • 25
  • 35
  • take a look at this link where I have posted some code examples and demo video's of how I got it working quite reliably. It shows the local directories and the iCloud directories being created and cleared.http://ossh.com.au/design-and-technology/software-development/uimanageddocument-icloud-integration/. – Duncan Groenewald Dec 11 '13 at 22:43
  • Cool, thanks Duncan. This documentation looks real promising :) – Nathan Bruno Dec 18 '13 at 17:20
1

For iCloud core-data content you want to call the static method removeUbiquitousContentAndPersistentStoreAtURL:options:error: on the NSPersistentStoreCoordinator class, then call removeItemAtURL:error:

See deleteManagedDocumentWithIdentifier: in my APManagedDocument project. This is on the ubiquitous_experiment branch which I am currently working on finalizing before I merge it back down to the master branch.

dtrotzjr
  • 928
  • 5
  • 18
  • And is this supposed to remove the file from other devices too or am I supposed have logic in the app on other devices to detect that the file is no longer in iCloud and do the same thing on that device ? And what is the logic for detecting that the file has been removed ? Any documentation from Apple ? – Duncan Groenewald Oct 09 '13 at 05:26
  • The call to `removeUbiquitousContentAndPersistentStoreAtURL:options:error` will remove the Core Data transaction logs from iCloud and remove the persistent store file, the call to `removeItemAtURL:error` will remove the `UIManagedDocument` package. Now that I think about it since I store my documents in the ubiquitous store I need to `setUbiquitous:NO` the document first so that iCloud forgets about that as well. See WWDC 2013 Session 207 for more on `removeUbiquitousContentAndPersistentStoreAtURL:options:error` – dtrotzjr Oct 09 '13 at 14:45
  • Sure but what happens on other devices when the app starts up on them ? Bearing in mind they probably still have a working copy of the database, I don't see a notification in the documents for Core Data to tell us 'Oops someone deleted everything in the cloud, what do you want to do now: a) build a new copy and put it back in the cloud, b) keep your copy and make it local only, c) delete your copy too or d) let us decide ?" – Duncan Groenewald Oct 09 '13 at 23:27
  • This is just totally weird - now I have the mac online too !! This is nuts, I just open my existing sqlite files and then run migrate on the file, and thats it they're in the cloud, they don't even move anywhere themselves. Done, kaput! Too easy! I did have to turn off sandbox to open any file on the desktop. Core Data creates a CoreDataUbiquitySupport folder in the same directory as the document which has the fallback stores and stuff. Surely its not possible they have made it this easy. – Duncan Groenewald Oct 10 '13 at 00:47
  • Did you watch the WWDC Video? they have a callback that takes place when the persistentStore is going to be removed and or changed and the app is still running. – dtrotzjr Oct 10 '13 at 01:04
  • Yes, but I was under the impression it was only during startup! Reading the transcript again though... _"Now, I need to mention that this is a special case scenario. You will only see these notifications during our asynchronous setup process if there is no persistent store file on disk, or there are has been a change to the iCloud account **or the contents of the container since we last launched**."_ – Duncan Groenewald Oct 10 '13 at 03:06
  • Awesome, I had forgotten to set the persistentStore options, before opening prior to the delete but that's working fine now. I have just switched a bunch of my desktop files to iCloud and they have all migrated across fine too and some are around 100MB. – Duncan Groenewald Oct 10 '13 at 06:18