NSMetadataQuery enableUpdates

1.7k Views Asked by At

I am having trouble understanding how updates work with an NSMetadataQuery.

I am trying to determine whether a file has finished downloading from iCloud. My initial query tells me clearly enough the the file is not downloaded and I can start the download, but I want to put up a progress bar if it is going to take any time to download the file. I have invoked enableUpdates, but it doesn't seem to alter either the downloading/downloaded status or the percent downloaded even though I am fairly certain the file is downloading. (I get stuck in a while loop. If I quit and rerun the app, it sees the files as downloaded and skips the while loop.)

Do I have to start a new query to get updates? If so, what is the function of the enableUpdates and disableUpdates?

Is there some different way the initial query has to be invoked in order to get updates? I got this impression from something in the documentation but I couldn't find any details that seemed to explain how.

2

There are 2 best solutions below

5
On

Very good sample code and explanation from Apple here:

https://developer.apple.com/library/ios/#documentation/DataManagement/Conceptual/DocumentBasedAppPGiOS/ManageDocumentLifeCycle/ManageDocumentLifeCycle.html#//apple_ref/doc/uid/TP40011149-CH4-SW6

Basically you just leave the query running all the time (except when you go into the background). You get a notification whenever there's a change in the situation, and you maintain your document lists accordingly. A document that has not yet been downloaded from the cloud is initially a placeholder; as you can see from the next section, "Downloading Document Files from iCloud", the download won't happen until you ask it to with startDownloadingUbiquitousItemAtURL:error: (or try to read the document with openWithCompletionHander:).

2
On

I have managed to work through this but it is a classic case of trying so many different things and running into so many brick walls that I no longer remember exactly what I did that cured the problem, much less why I had the problem in the first place. Maybe I can share a couple things that I came across.

One is a blog at http://blog.wadetregaskis.com/icloud-documentation-is-crap/. This paragraph explains how NSMetadatQuery really works:

[This] explains something crucial about NSMetadataQuery: Long story short, NSMetadataQueryDidUpdateNotification does not do what you might expect. Certainly not what I expected. I read the documentation as saying that it would be used to deliver results, and NSMetadataQueryDidFinishGatheringNotification would be posted when the full first pass had completed. That’s a very typical pattern used elsewhere in Apple’s APIs (including Spotlight, so one would assume NSMetadataQuery would work the same). But it doesn’t.

Instead, all of the first full run’s results are buffered up and provided by NSMetadataQueryDidFinishGatheringNotification. NSMetadataQueryDidUpdateNotification is purely for subsequent, real-time changes.

Another thing that I think may have been causing me problems is that I may have had more than one instance of NSMetadataQuery active at the same time. I'm not sure and I don't know why that would prevent either of them from sending an update notification.

At any rate the following code now works for me:

if (usingIcloud) {
    if (query) [query disableUpdates];

    query.predicate = [NSPredicate predicateWithFormat:@"%K like '*.caf' or %K like '*.mov'", NSMetadataItemFSNameKey, NSMetadataItemFSNameKey];
    query.searchScopes = [NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope];
    
    [[NSNotificationCenter defaultCenter]
         addObserver:self
         selector:@selector(updateUbiquitousDocuments:)
         name:NSMetadataQueryDidFinishGatheringNotification
         object:nil];
    
    [[NSNotificationCenter defaultCenter]
         addObserver:self
         selector:@selector(updateUbiquitousProgress:)
         name:NSMetadataQueryDidUpdateNotification
         object:nil];
    
    [query enableUpdates];
}

I am able to get updates which tell me how much of a given file has downloaded in my updateUbiquitousProgress method and let it run a progress bar. If anyone wants to know more or see more of the code that ended up working, I'd be happy to oblige.