Hi all,
I’m trying to use NSMetadataQuery on iOS to track changes to folders users have imported from elsewhere but, no matter what I try, I get no results.
Following the documentation for searching file metadata with NSMetadataQuery,
I’m creating a live query (albeit in Swift) and listening for […]QueryDidFinishGathering
and […]QueryDidUpdate
. The former fires, with no results, and the latter never fires.
I’ve also tried following the Synchronizing Documents in the iCloud Environment example, adding the appropriate Ubiquity keys to my Info.plist
and .entitlements
file, with no change.
I’m importing files and folders using SwiftUI’s View.fileImporter(isPresented:allowedContentTypes:allowsMultipleSelection:onCompletion:)
, but can’t see how I might security-scope the NSMetadataQuery’s execution (if that’s even a thing?).
My test project is on GitHub, but the main parts are below…
My query method:
extension NSMetadataQueryUbiquitousExternalDocumentsTestApp {
func findAccessibleFiles() {
query.stop()
fileMonitor?.cancel()
fileMonitor = Publishers.MergeMany(
[
.NSMetadataQueryDidFinishGathering,
.NSMetadataQueryDidUpdate
].map { NotificationCenter.default.publisher(for: $0) }
)
.receive(on: DispatchQueue.main)
.sink { notification in
query.disableUpdates()
defer { query.enableUpdates() }
foundItems = query.results as! [NSMetadataItem]
print("Query posted \(notification.name.rawValue) with results: \(query.results)")
}
query.searchScopes = [
NSMetadataQueryAccessibleUbiquitousExternalDocumentsScope
]
query.predicate = NSPredicate(
format: "%K LIKE %@",
argumentArray: [NSMetadataItemFSNameKey, "*"]
)
query.sortDescriptors = [
NSSortDescriptor(key: NSMetadataItemFSNameKey, ascending: true)
]
if query.start() {
print("Query started")
} else {
print("Query didn't start for some reason")
}
}
}
Info.plist:
[…]
<key>NSUbiquitousContainers</key>
<dict>
<key>iCloud.com.stevemarshall.AnnotateML</key>
<dict>
<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>
<key>NSUbiquitousContainerName</key>
<string>AnnotateML</string>
<key>NSUbiquitousContainerSupportedFolderLevels</key>
<string>ANY</string>
</dict>
</dict>
[…]
I eventually raised a TSI for this, and Developer Technical Support indicated that I should file a bug with NSMetadataQueryAccessibleUbiquitousExternalDocumentsScope
“since it doesn’t behave as documented”. I've filed that as FB9631965.
In the mean-time, I've discovered that NSFilePresenter
's documentation describes it as “The interface […] to inform an object […] about changes to that file”, and allows us to monitor imported directories for changes! 🎉
It does, however, have some decade-old bugs that mean the only subitem-related method that actually works consistently is presentedSubitemDidChange(at:)
. It's a bit of a blunt instrument, but it'll do for my use case.