How to receive all notifications from an NSMetadataQuery running inside a plug-in (NSBundle)
I regularly use plug-ins (loaded NSBundles) to encapsulate some functionality. I now want to use NSMetadataQuery in one of my plug-ins, but ran into threading problems I'm unable to solve.
Inside the main class of the plug-in, I set up the query like this:
NSMetadataQuery *mdQuery = [[NSMetadataQuery alloc] init];
[mdQuery setPredicate:[NSPredicate predicateWithFormat:@"(kMDItemFSName LIKE 'Project *')"]];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(processQuery:)
name:nil
object:mdQuery];
[mdQuery startQuery];
And the notifications are caught by:
- (void)processQuery:(NSNotification *)notification
{
NSMetadataQuery *mdQuery = [notification object];
if ([[notification name] isEqualToString:NSMetadataQueryDidStartGatheringNotification]) {
NSLog(@"%@ %@ Query started", [self class], NSStringFromSelector(_cmd));
} else if ([[notification name] isEqualToString:NSMetadataQueryGatheringProgressNotification]) {
NSLog(@"%@ %@ %ld", [self class], NSStringFromSelector(_cmd), (long)[mdQuery resultCount]);
} else if ([[notification name] isEqualToString: NSMetadataQueryDidFinishGatheringNotification]) {
NSUInteger theResultCount = [mdQuery resultCount];
theResultCount = 10; //for now
for (NSUInteger i; i < theResultCount; i++) {
NSLog(@"%@ %@ %ld %@", [self class], NSStringFromSelector(_cmd), (long)i, [mdQuery resultAtIndex:i]);
}
} else {
NSLog(@"%@ %@ NSMetadataQueryDidUpdateNotification: %@", [self class], NSStringFromSelector(_cmd), notification);
}
}
This code works fine running in an app, but 开发者_C百科when run from with the plug-in, only NSMetadataQueryDidStartGatheringNotification is ever received, nothing else.
I found one or two posts of people wrestling with the same problem, and one of them (James Bucanek in Oh notification, where are you?) solved his problem by calling CFRunLoopRun(); right after the startQuery and CFRunLoopStop(CFRunLoopGetCurrent ()); when the query was done. One problem is that the run loop thus started is synchronous while NSMetadataQuery clearly is asynchronous, the other was that in the plug-in it never got past NSMetadataQueryGatheringProgressNotification. I then tried giving NSMetadataQuery its own thread but again, only NSMetadataQueryDidStartGatheringNotification was ever received. I don't know if the problem can be solved, but I would really like some input.
Replace:
NSMetadataQuery *mdQuery = [[NSMetadataQuery alloc] init];
// ...
[mdQuery startQuery];
with:
dispatch_async(dispatch_get_main_queue(), ^{
NSMetadataQuery *mdQuery = [[NSMetadataQuery alloc] init];
// ...
[mdQuery startQuery];
});
(If you need to target Leopard or earlier, use -performSelectorOnMainThread:withObject:waitUntilDone:
instead.)
There shouldn't be anything different occurring if the code is loaded via bundle instead of compiled into the app.
When you load a Cocoa bundle the classes in the bundle are loaded into the app's address space and essentially become part of the app. Bundle code is not run in a separate thread or run loop unless you specifically make it so.
I don't believe this is a run loop or threading issue. What makes you think it is?
Are you sure the object in your bundle that begins the query has not been deallocated by the time the results return? What is holding on to it?
精彩评论