Question

I can't find an obvious way to detect deletion of a document that I'm monitoring (I cache a list of docs my app cares about).

On Device1: When I delete a doc, I call

        [fileCoordinator coordinateWritingItemAtURL:fileURL options:NSFileCoordinatorWritingForDeleting
          error:&err byAccessor:^(NSURL* writingURL) {
             [fileManager removeItemAtURL:writingURL error:nil];

This works fine on Device1, everything stays in synch. On Device2: I was trying to rely on NSMetadataQuery notifications:

Initial file list is coming in fine on NSMetadataQueryDidFinishGatheringNotification Document adds/changes are coming in fine via NSMetadataQueryDidUpdateNotification

When i delete a file on Device1, I get a strange result: an update comes in NSMetadataQueryDidUpdateNotification with all my docs (except the one deleted) listed I'm not sure how I am supposed to detect that the missing file was deleted or that the update notification was for that purpose

Question 1: What should I be checking for?

I tried another route which was to register as a NSFilePresenter for the iCloud URL:

- (NSURL *)iCloudDocumentsURL
{
    return [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil] URLByAppendingPathComponent:@"Documents"];
}

I now get called via the NSFilePresenter protocol when files in that URL change, but it's punitively slow to run the logic to determine the missing doc since the callback is vague. The only call I get back is - (void)presentedItemDidChange; I was expecting to get a callback via - (void)accommodatePresentedSubitemDeletionAtURL:(NSURL *)url completionHandler:(void (^)(NSError *errorOrNil))completionHandler But this method is never called.

Question 2: Any idea how to get that working?

Was it helpful?

Solution

Since you're keeping track of files previously reported from iCloud, the deleted file is absent from the current iCloud listing, and so you just compare the two lists to find which was deleted.

That's what I'm doing in my "file manager" view controller, because I keep a NSMutableDictionary of file entries, which includes among other things, keys for the positions of the file "icons" in my master view. When I get notified of an update, and that update results in either more or fewer files, I animate the icon changes based upon those file changes.

OTHER TIPS

tobinjim is correct in that the NSMetadataQuery returns the entire result set every time. I had expected that only changes to be sent to save bandwidth, but I did not RTFM correctly.

Once I figured that out, I ran into a bug in iOS libraries. This was the crash that was occurring when I deleted a document on one device and the iCloud query update came across to my other device:

    2012-06-25 13:15:12.343 app[19779:707] *** -[NSMutableIndexSet indexGreaterThanOrEqualToIndex:]: message sent to deallocated instance 0xdaae2c0
    (gdb) bt
    #0  0x31937870 in ___forwarding___ ()
    #1  0x31892650 in __forwarding_prep_0___ ()
    #2  0x373cc676 in __NSIndexSetEnumerate ()
    #3  0x373a1ee8 in -[NSIndexSet enumerateIndexesWithOptions:usingBlock:] ()
    #4  0x371c1f08 in -[LBQuery _processUpdates] ()
    #5  0x373571a6 in -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:modes:] ()
    #6  0x3737ffa4 in -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:] ()
    #7  0x371c2274 in -[LBQuery processUpdates] ()
    #8  0x373a88d6 in -[NSMetadataQuery _update] ()

I believe I have found the cause of this issue. I was reviewing the new IOS 6 sample code from the presentation by Luke the Hiesterman. I noticed that there were no calls to NSMetadataQuery disable/enableUpdates like there were in the previous iCloud sample apps. I removed all calls to these. I also changed my method which handled NSMetadataQueryDidUpdateNotification calls to run asynchronously but in a queued manner.

There seems to be a race condition occurring between threads for NSMetadataQuery. In some calls the results of the query are fine but at other times, they have been released and the results show up as NSZombie's (thanks to gdb which is way way better than the current lldb). So the enabling and disabling of the query across threads causes the LBQuery to crash by calling objects that have been released.

The removal of all the enabling and disabling for NSMetadataQuery seems to have sped up my app as well, and iCloud seems much more stable.

Since iOS 8 NSMetadataQuery extended NSMetadataQueryDidUpdateNotification userInfo with NSMetadataQueryUpdateRemovedItemsKey which you can use to detect which files were removed.

https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSMetadataQuery_Class/#//apple_ref/doc/constant_group/Keys_for_Use_with_a_Notification_Info_Dictionary

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top