Как получать все уведомления от NSMetadataQuery, работающего внутри подключаемого модуля (NSBundle)

Я регулярно использую плагины (загруженные 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 и ничего больше.

Я нашел один или два поста людей, борющихся с одной и той же проблемой, и один из них (Джеймс Буканек в уведомлении О, где ты?) решил свою проблему, вызвав CFRunLoopRun(); сразу после startQuery и CFRunLoopStop(CFRunLoopGetCurrent()); когда запрос был выполнен. Одна проблема заключается в том, что запущенный таким образом цикл выполнения является синхронным, в то время как NSMetadataQuery явно является асинхронным, а другая заключается в том, что в подключаемом модуле он никогда не проходил дальше NSMetadataQueryGatheringProgressNotification. Затем я попытался дать NSMetadataQuery свой собственный поток, но снова было получено только NSMetadataQueryDidStartGatheringNotification. Я не знаю, может ли проблема быть решена, но мне бы очень хотелось, чтобы некоторые советы.


person Elise van Looij    schedule 06.06.2011    source источник


Ответы (2)


Заменять:

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

с участием:

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

(Если вам нужно настроить таргетинг на Leopard или более раннюю версию, используйте вместо этого -performSelectorOnMainThread:withObject:waitUntilDone:.)

person hatfinch    schedule 19.07.2011

Не должно быть ничего другого, если код загружается через пакет, а не компилируется в приложение.

Когда вы загружаете пакет Cocoa, классы в пакете загружаются в адресное пространство приложения и по существу становятся частью приложения. Пакетный код не запускается в отдельном потоке или цикле выполнения, если вы не сделаете это специально.

Я не верю, что это проблема цикла выполнения или потоковой передачи. Что заставляет вас думать, что это так?

Вы уверены, что объект в вашем пакете, с которого начинается запрос, не был освобожден к моменту возврата результатов? Что на нем держится?

person Rob Keniger    schedule 07.06.2011
comment
Объект поиска у меня не сохраняется, потому что в этом нет необходимости. Я запускал код с сохраненным объектом поиска и без него как в приложении, так и в плагине, и результат всегда один и тот же: поиск доходит до конца при запуске в приложении, но не при запуске в плагине. -в. Что касается цикла выполнения: проблема не в том, что плагин запускается в отдельном цикле, проблема в том, что код плагина вообще не имеет цикла выполнения. Почему я так думаю? Потому что так говорят Джеймс Буканек (см. ссылку в моем вопросе) и другие, и у меня нет причин сомневаться в них. - person Elise van Looij; 07.06.2011
comment
Я перефразирую бит цикла выполнения: насколько я могу понять, код подключаемого модуля запускается циклом выполнения приложения, но он не сохраняется достаточно долго, чтобы подключаемый модуль мог получать уведомления, отличные от самого первого. , уведомление о начале, которое публикуется сразу. - person Elise van Looij; 07.06.2011
comment
Когда вы говорите, что он не хранится достаточно долго, что вы имеете в виду? Ваш плагин должен иметь класс, который вы где-то создаете. Этот экземпляр должен находиться достаточно долго, чтобы получить уведомление. Как вы загружаете код в свой плагин? Сохраняется ли экземпляр объекта подключаемого модуля? Если нет, вероятно, он просто автоматически освобождается и освобождается, поэтому, конечно, он не может ответить на уведомление. Плагины — это не волшебство, они просто добавляют классы в ваше приложение. - person Rob Keniger; 08.06.2011
comment
Я ценю тот факт, что вы взяли на себя труд ответить на мой вопрос, но я чувствую, что это превращается в своего рода словесный пинг-понг. Я широко использую плагины, они управляют представлениями и постоянными хранилищами, реагируют на уведомления и отправляют их и многое другое. Но, видимо, в асинхронном процессе есть что-то, что не очень хорошо сочетается с архитектурой плагинов, и я надеюсь узнать, что это такое. - person Elise van Looij; 08.06.2011
comment
Я не пытаюсь спорить, я всего лишь спрашиваю, уверены ли вы, что проблема связана с тем, что код загружается из плагина? Не может ли быть другой причины? - person Rob Keniger; 09.06.2011
comment
Код в моем вопросе я написал и сначала запустил в приложении. Сообщения NSLog для каждого уведомления, вплоть до NSMetadataQueryDidFinishGatheringNotification. Я вырезал и вставил точно такой же код в подключаемый модуль, и единственный NSLog, который я когда-либо получал, был для NSMetadataQueryDidStartGatheringNotification. Когда я добавил цикл выполнения, я получил сообщения для NSMetadataQueryGatheringProgressNotification, но никогда не для уведомления о завершении. Я описал все это в своем вопросе или думал, что сделал. Я был трезв и в разумных пределах, когда я сделал все это. - person Elise van Looij; 09.06.2011
comment
Причина, по которой я спрашиваю, заключается в том, что у меня есть подключаемый модуль, который запускает поиск в центре внимания, и я никогда не сталкивался с этой проблемой. Я, однако, пойду и перепроверю это! - person Rob Keniger; 10.06.2011