2

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.

  • Worth looking at this too: http://stackoverflow.com/questions/9675303/icloud-callback-for-nsfilemanagers-startdownloadingubiquitousitematurl – matt May 02 '13 at 17:25

2 Answers2

2

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.

Community
  • 1
  • 1
  • I know this is old now but I'm struggling with the same thing and would be very interested to see more of your working code – SeanR Mar 06 '16 at 10:07
  • I haven't looked at this code for almost 3 years, but I'll send you the whole project if there is some way to do it other than posting text on this site. You can contact me at richard@rgpost.com. – Richard Patterson Mar 06 '16 at 19:30
0

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:).

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • I am not using a UIDocument, but simply writing video files to iCloud and then trying to play them on the second device. My query is still running so far as I know and the initial results tell me that the file in question has not been downloaded. So I use startDownloadingUbiquitousItemAtURL:error to start downloading the file but I never get an update that it has completed downloading or one indicating that any percent of it has downloaded. From what you say it sounds as though I should just be able to periodically check the key of the metadata item to see how much has been downloaded. – Richard Patterson May 02 '13 at 16:32
  • "So I use `startDownloadingUbiquitousItemAtURL:error:`" Well, golly, you might have mentioned that in your question. It would be helpful if your question showed some actual detail about what you are *actually* doing and what the precise problem is. – matt May 02 '13 at 16:38
  • "writing video files to iCloud and then trying to play them on the second device" Is this really something you want to do? Will users be happy at having their iCloud quota or their background bandwidth eaten away by video files? I wonder whether this is a good use of iCloud. Just a thought... – matt May 02 '13 at 16:41
  • Sorry if my question was not specific enough. My problem is that I do not seem to get updates from a query even though I have the query running and have invoked enableUpdates. The value of NSMetadataUbiquitousItemPercentDownloadedKey seems to remain 0. – Richard Patterson May 02 '13 at 17:17
  • You're not the first person to notice that. Take a look at this: http://stackoverflow.com/questions/8801372/icloud-doesnt-update-the-download-precess and this: http://stackoverflow.com/questions/11035276/why-isnt-startdownloadingubiquitousitematurlfileurl-starting-a-download-of-th – matt May 02 '13 at 17:24