3

I’m trying to explore the files available to my app in iCloud using NSMetaDataQuery. I’m able to start the query, but it never finishes. Here’s my code.

func report1() {
    let filemgr = FileManager.default
    let url = filemgr.url(forUbiquityContainerIdentifier: nil)
    guard url != nil else {
        print("url is nil")
        return
    }
    let metaDataQuery = NSMetadataQuery()
    metaDataQuery.predicate =
        NSPredicate(format: "%K like '*'", NSMetadataItemFSNameKey)
    metaDataQuery.searchScopes = [NSMetadataQueryUbiquitousDocumentsScope]
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(didFinish),
                                           name: NSNotification.Name.NSMetadataQueryDidFinishGathering,
                                           object: nil)
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(didStart),
                                           name: NSNotification.Name.NSMetadataQueryDidStartGathering,
                                           object: nil)
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(didUpdate),
                                           name: NSNotification.Name.NSMetadataQueryDidUpdate,
                                           object: nil)
    let result = metaDataQuery.start()
    print("metaDataQuery.start() returned \(result)")
}

@objc func didStart(notification: NSNotification) {
    let query: NSMetadataQuery = notification.object as! NSMetadataQuery
    print("didStart found \(query.results.count) items")
}

@objc func didFinish(notification: NSNotification) {
    print("didFinish")
}

@objc func didUpdate(notification: NSNotification) {
    print("didUpdate")
}

This prints the following:

didStart found 0 items
metaDataQuery.start() returned true

didStart is getting called, but didFinish and didUpdate are never called. I get the same results if I substitute == or ==[cd] for like in the predicate. Changing NSMetadataQueryUbiquitousDocumentsScope to NSMetadataQueryUbiquitousDataScope has no effect. What am I missing?

The same issue seems to have been posed several times on this forum, but I'm not finding any satisfactory answers.

Jerry Agin
  • 629
  • 1
  • 5
  • 15

3 Answers3

2

I think I found what is the reason. Your code

let metaDataQuery = NSMetadataQuery()

This actually makes the metaDataQuery as local object, its lifecycle is in the function scope, and will be destroyed when the function ends. Then how can it work? Please make it as a member field.

marknote
  • 1,058
  • 8
  • 10
  • 1
    No, that doesn't work either. I moved the declaration to the object scope and got the same result. I think it's because the local variable is actually a pointer to the NSMetadataQuery object. Calling metaDataQuery.start() will cause a copy of the pointer to be cached in the implementing code, so the object will not be garbage collected. – Jerry Agin Apr 05 '17 at 19:35
2

For me, the problem was I wasn't calling query.start() from the main thread (I found the solution here.

For me the fix was as simple as:

DispatchQueue.main.async {
    self.query.start()
}
Ogre Codes
  • 18,693
  • 1
  • 17
  • 24
0

Change

    NSPredicate(format: "%K like '*'", NSMetadataItemFSNameKey)

to

    NSPredicate(format: "%K like '*.*'", NSMetadataItemFSNameKey)
marknote
  • 1,058
  • 8
  • 10