【问题标题】:How to receive all notifications from an NSMetadataQuery running inside a plug-in (NSBundle)如何从插件(NSBundle)内运行的 NSMetadataQuery 接收所有通知
【发布时间】:2011-07-20 06:10:08
【问题描述】:

我经常使用插件(加载的 NSBundles)来封装一些功能。我现在想在我的一个插件中使用 NSMetadataQuery,但遇到了我无法解决的线程问题。

在插件的主类中,我这样设置查询:

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];

通知被以下人员捕获:

- (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);
    }
}

此代码在应用程序中运行良好,但使用插件运行时,只收到 NSMetadataQueryDidStartGatheringNotification ,没有其他内容。

我发现一两个帖子里有同样问题的人,其中一个 (James Bucanek in Oh notification, where are you?) 通过调用 CFRunLoopRun(); 解决了他的问题;在 startQuery 和 CFRunLoopStop(CFRunLoopGetCurrent ()) 之后;当查询完成时。一个问题是这样启动的运行循环是同步的,而 NSMetadataQuery 显然是异步的,另一个是在插件中它从未通过 NSMetadataQueryGatheringProgressNotification。然后我尝试给 NSMetadataQuery 自己的线程,但同样,只收到了 NSMetadataQueryDidStartGatheringNotification。我不知道问题是否可以解决,但我真的很想提供一些意见。

【问题讨论】:

    标签: cocoa nsnotificationcenter


    【解决方案1】:

    替换:

    NSMetadataQuery *mdQuery = [[NSMetadataQuery alloc] init];
    // ...
    [mdQuery startQuery];
    

    与:

    dispatch_async(dispatch_get_main_queue(), ^{
        NSMetadataQuery *mdQuery = [[NSMetadataQuery alloc] init];
        // ...
        [mdQuery startQuery];
    });
    

    (如果您需要定位 Leopard 或更早版本,请改用 -performSelectorOnMainThread:withObject:waitUntilDone:。)

    【讨论】:

      【解决方案2】:

      如果代码是通过包加载而不是编译到应用程序中,则应该不会发生任何不同。

      当您加载 Cocoa 包时,包中的类会被加载到应用程序的地址空间中,并且本质上会成为应用程序的一部分。除非您特别指定,否则捆绑代码不会在单独的线程或运行循环中运行。

      我认为这不是运行循环或线程问题。是什么让你认为它是?

      您确定包中开始查询的对象在结果返回时还没有被释放吗?是什么在坚持?

      【讨论】:

      • 我没有保留搜索对象,因为它不需要。我已经在应用程序和插件中运行了带有和不带有保留搜索对象的代码,结果始终相同:在应用程序中运行时搜索完成,但在插件中运行时没有-在。至于run loop:问题不在于插件运行在单独的循环中,问题在于插件代码根本没有run loop。为什么我会这么认为?因为 James Bucanek(请参阅我的问题中的链接)和其他人这么说,我没有理由怀疑他们。
      • 我将改写运行循环位:据我所知,插件代码由应用程序的运行循环运行,但它的保存时间不足以让插件运行接收除第一个通知之外的通知,即立即发布的开始通知。
      • 当你说“它的保存时间不够长”时,你指的是什么?您的插件必须有一个您在某处实例化的类。该实例必须停留足够长的时间才能接收到通知。您如何在插件中加载代码?插件对象的实例是否保留?如果没有,它可能只是被自动释放和释放,所以它当然无法响应通知。插件并不神奇,它们只是为您的应用添加类。
      • 我很欣赏你不厌其烦地回答我的问题,但我觉得这正在退化为一种口头乒乓球。我广泛使用插件,它们管理视图和持久存储、响应和发送通知等等。但显然,异步进程与插件架构不兼容,我希望了解它是什么。
      • 我不想争论,我只想问你确定问题是由于代码是从插件加载的吗?难道没有别的原因吗?
      猜你喜欢
      • 2019-03-20
      • 2018-02-12
      • 2012-01-08
      • 2014-06-21
      • 2014-12-12
      • 2015-07-13
      • 2011-03-08
      • 2020-04-16
      • 2011-07-03
      相关资源
      最近更新 更多