问题
I'm trying to get up and running with an NSMetadataQueryDidUpdateNotification
on an OS X app, to alert me when a file in my iCloud ubiquity container is updated. I've been doing a lot of research (including reading other Stack answers like this, this, this, and this), but I still don't have it quite right, it seems.
I've got a "CloudDocument" object subclassed from NSDocument, which includes this code in the H:
@property (nonatomic, strong) NSMetadataQuery *alertQuery;
and this is the M file:
@synthesize alertQuery;
-(id)init {
self = [super init];
if (self) {
if (alertQuery) {
[alertQuery stopQuery];
} else {
alertQuery = [[NSMetadataQuery alloc]init];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryDidUpdate:) name:NSMetadataQueryDidUpdateNotification object:nil];
NSLog(@"Notification created");
[alertQuery startQuery];
}
return self;
}
-(void)queryDidUpdate:(NSNotification *)notification {
NSLog(@"Something changed!!!");
}
According to my best understanding, that should stop a pre-existing query if one is running, set up a notification for changes to the ubiquity container, and then start the query so it will monitor changes from here on out.
Except, clearly that's not the case because I get Notification created
in the log on launch but never Something changed!!!
when I change the iCloud document.
Can anyone tell me what I'm missing? And if you're extra-super-sauce awesome, you'll help me out with some code samples and/or tutorials?
Edit: If it matters/helps, there is only one file in my ubiquity container being synced around. It's called "notes", so I access it using the URL result from:
+(NSURL *)notesURL {
NSURL *url = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
return [url URLByAppendingPathComponent:kAllNotes];
}
where "kAllNotes" is set with #define kAllNotes @"notes"
.
EDIT #2: There have been a lot of updates to my code through my conversation with Daij-Djan, so here is my updated code:
@synthesize alertQuery;
-(id)init {
self = [super init];
if (self) {
alertQuery = [[NSMetadataQuery alloc] init];
if (alertQuery) {
[alertQuery setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
NSString *STEDocFilenameExtension = @"*";
NSString* filePattern = [NSString stringWithFormat:@"*.%@", STEDocFilenameExtension];
[alertQuery setPredicate:[NSPredicate predicateWithFormat:@"%K LIKE %@", NSMetadataItemFSNameKey, filePattern]];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryDidUpdate:) name:NSMetadataQueryDidFinishGatheringNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryDidUpdate:) name:NSMetadataQueryDidUpdateNotification object:nil];
NSLog(@"Notification created");
[alertQuery startQuery];
}
return self;
}
-(void)queryDidUpdate:(NSNotification *)notification {
[alertQuery disableUpdates];
NSLog(@"Something changed!!!");
[alertQuery enableUpdates];
}
回答1:
How do you save your document - what url do you give it? Unless you give it an extension yourself, it won't automatically be given one - so your *.*
pattern will never match a file that does not have an extension. Try *
as the pattern and see what happens.
Also, it helps to log what is happening within queryDidUpdate, until you've worked out exactly what's going on :
Try something like:
-(void)queryDidUpdate:(NSNotification *)notification {
[alertQuery disableUpdates];
NSLog(@"Something changed!!!");
// Look at each element returned by the search
// - note it returns the entire list each time this method is called, NOT just the changes
int resultCount = [alertQuery resultCount];
for (int i = 0; i < resultCount; i++) {
NSMetadataItem *item = [alertQuery resultAtIndex:i];
[self logAllCloudStorageKeysForMetadataItem:item];
}
[alertQuery enableUpdates];
}
- (void)logAllCloudStorageKeysForMetadataItem:(NSMetadataItem *)item
{
NSNumber *isUbiquitous = [item valueForAttribute:NSMetadataItemIsUbiquitousKey];
NSNumber *hasUnresolvedConflicts = [item valueForAttribute:NSMetadataUbiquitousItemHasUnresolvedConflictsKey];
NSNumber *isDownloaded = [item valueForAttribute:NSMetadataUbiquitousItemIsDownloadedKey];
NSNumber *isDownloading = [item valueForAttribute:NSMetadataUbiquitousItemIsDownloadingKey];
NSNumber *isUploaded = [item valueForAttribute:NSMetadataUbiquitousItemIsUploadedKey];
NSNumber *isUploading = [item valueForAttribute:NSMetadataUbiquitousItemIsUploadingKey];
NSNumber *percentDownloaded = [item valueForAttribute:NSMetadataUbiquitousItemPercentDownloadedKey];
NSNumber *percentUploaded = [item valueForAttribute:NSMetadataUbiquitousItemPercentUploadedKey];
NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
BOOL documentExists = [[NSFileManager defaultManager] fileExistsAtPath:[url path]];
NSLog(@"isUbiquitous:%@ hasUnresolvedConflicts:%@ isDownloaded:%@ isDownloading:%@ isUploaded:%@ isUploading:%@ %%downloaded:%@ %%uploaded:%@ documentExists:%i - %@", isUbiquitous, hasUnresolvedConflicts, isDownloaded, isDownloading, isUploaded, isUploading, percentDownloaded, percentUploaded, documentExists, url);
}
回答2:
you never allocate your alertQuery....
somewhere you need to alloc,init a NSMetaDataQuery for it
example
NSMetadataQuery* aQuery = [[NSMetadataQuery alloc] init];
if (aQuery) {
// Search the Documents subdirectory only.
[aQuery setSearchScopes:[NSArray
arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
// Add a predicate for finding the documents.
NSString* filePattern = [NSString stringWithFormat:@"*"];
[aQuery setPredicate:[NSPredicate predicateWithFormat:@"%K LIKE %@",
NSMetadataItemFSNameKey, filePattern]];
// Register for the metadata query notifications.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(processFiles:)
name:NSMetadataQueryDidFinishGatheringNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(processFiles:)
name:NSMetadataQueryDidUpdateNotification
object:nil];
// Start the query and let it run.
[aQuery startQuery];
}
processFiles method
== your queryDidUpdate
- processFiles(NSNotification*)note {
[aQuery disableUpdates];
.....
[aQuery enableUpdates];
}
NOTE: disable and reenable search there!
see:
http://developer.apple.com/library/ios/#documentation/General/Conceptual/iCloud101/SearchingforiCloudDocuments/SearchingforiCloudDocuments.html
来源:https://stackoverflow.com/questions/17129946/setting-up-nsmetadataquerydidupdatenotification-for-a-simple-response