Reputation: 2069
I am monitoring my iCloud sandbox (iOS) using an NSMetaDataQuery
are recommended - and all is working well.
I'm attempting to use the NSMetadataQueryUpdateChangedItemsKey
in the NSMetadataQueryDidUpdateNotification
in order to efficiently update my internal model of the file system. Challenge I have is that when a file is moved/renamed, how can I know the original file path - so I can update my model?
It appears that the NSMetaDataItem
objects are persistent (i.e. the same object instance is updated when the path changes) so I could use the pointer value as a kind of index into my model. However - I'd be taking advantage of an apparent implementation detail (which could change.) Perhaps NSMetaDataItems
are recycled when memory runs low?
Anyone know how this should be done (or if it is actually the case that NSMetaDataItem
objects persist for the lifetime of the NSMetaDataQuery
- and stay 'attached' to the same file system item.)
Upvotes: 3
Views: 509
Reputation: 12240
Documentation mentions that results are suitable for Cocoa Bindings, which means that most likely those objects are persistent.
I use more hardcore combination of NSFilePresenter
and NSMetadataQuery
running side by side to monitor documents in container. NSFilePresenter
has convenient API for detecting when files were being moved:
func presentedSubitem(at oldURL: URL, didMoveTo newURL: URL)
For that to work though when you move files in container you have to explicitly notify file coordinator that you're moving file (see points 1-3):
let fc = NSFileCoordinator()
var error: NSError?
fc.coordinate(writingItemAt: from, options: .forMoving, writingItemAt: to, options: .forReplacing, error: &error, byAccessor: {
(fromURL, toURL) in
do {
// 1
fc.item(at: fromURL, willMoveTo: toURL)
try FileManager.default.moveItem(at: fromURL, to: toURL)
// 2
fc.item(at: fromURL, didMoveTo: toURL)
} catch {
// 3
fc.item(at: fromURL, didMoveTo: fromURL)
}
})
Upvotes: 0
Reputation: 338
Yes, the NSMetadataQuery doesn't provide a way to consult the previous path.
When an item is moved, its index in the NSMetadataQuery results remains the same. So we can duplicate the path of the results and when the update kicks in, we only need to check the NSMetadataItem at the exact position of the duplicated array.
if let updatedObj = obj.userInfo?[NSMetadataQueryUpdateChangedItemsKey] as! [NSMetadataItem]? {
for it in updatedObj {
let url = it.valueForAttribute(NSMetadataItemURLKey) as! NSURL
let value = it.valueForAttribute(NSMetadataUbiquitousItemIsUploadedKey) as! NSNumber
print("Path: " + url.path!)
print("Updated: " + value.stringValue)
let index = metaDataQuery.indexOfResult(it)
let prevPath = duplicatedPathArray[index]
if (prevPath != url.path!) {
print("File Moved. Previous path: " + prevPath)
duplicatePath()
}
}
}
Make sure you update the array each time a file is added or removed.
Upvotes: 2