NSMetadataQuery не заканчивает сбор (нет уведомления)


Я создаю менеджер резервного копирования для своего приложения (через iCloud). Я сделал несколько тестов, и основы сработали. Но через несколько дней все прекратилось. Я использую NSMetadataQuery для поиска, если файл резервной копии существует. Мои резервные файлы называются например Backup29112011154133.xml где числа представляют дату резервного копирования (форматируется как ddMMyyyyHHmmss). Я проверяю его в -viewDidAppear:

- (void)viewDidAppear:(BOOL)animated {
    [self checkForRemoteFile];
}

- (void)checkForRemoteFile {
    NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
    if (ubiq) {
        NSMetadataQuery *query = [[NSMetadataQuery alloc] init];
        [query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
        NSPredicate *pred = [NSPredicate predicateWithFormat:@"%K like 'Backup*'",NSMetadataItemFSNameKey];
        [query setPredicate:pred];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryDidFinishGathering:) name:NSMetadataQueryDidFinishGatheringNotification object:query];
        [query startQuery];
    } else {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"iCloud is unavailable at the moment" message:nil delegate:self cancelButtonTitle:@"Close" otherButtonTitles:nil];
        [alert setTag:TAG_ALERT_NOICLOUD];
        [alert show];
    }
}

- (void)queryDidFinishGathering:(NSNotification *)notif {
    NSMetadataQuery *query = [notif object];
    [query disableUpdates];
    [query stopQuery];
    [self loadRemoteFile:query];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSMetadataQueryDidFinishGatheringNotification object:query];
}

- (void)loadRemoteFile:(NSMetadataQuery *)query {
    if ([query resultCount] == 1) {
        canRestore = YES;
        NSMetadataItem *item = [query resultAtIndex:0];
        // parse the backup file
        [self.tableView reloadData];
    } else {
        canRestore = NO;
        modifDate = @"never";
        backupInfoLoaded = YES;
        [self.tableView reloadData];
    }
}

Проблема в том, что - (void)queryDidFinishGathering:(NSNotification *)notif никогда не выполняется. Я поставил туда брейкпинты и Нслоги, но ничего не произошло.

Я тоже пытался проверьте наличие других уведомлений, например "запрос действительно начал собираться" и "процесс запроса". Публикуется только уведомление "запрос запущен".

У меня также есть AppID с зарегистрированным iCloud и прикрепленным файлом прав.

Не могли бы вы помочь мне разобраться, что происходит? Может быть, я что-то пропустил?
4 5

4 ответа:

Во-первых, NSMetadataQuery не работает, если startQuery был вызван не из MaintThread. Существует вероятность, что предикат не работает и для каждого пути. Следующий код работает для меня.

NSURL *mobileDocumentsDirectoryURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
...
query.predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"%%K like \"%@*\"", [mobileDocumentsDirectoryURL path]], NSMetadataItemPathKey];
[query startQuery];

Исправлено путем создания ivar для NSMetadataQuery.

Я не знаю, почему приложение не может читать данные без NSMetadataquery ivar.

К сожалению, было много проблем с iCloud и использованием NSMetaDataQuery. Чтобы быть честным с вами, лучший источник на данный момент для всех ваших вопросов, связанных с iCloud, - это форумы разработчиков Apple. Сегодня Apple выпустила бета-версию iOS 5.1, и в примечаниях к выпуску по-прежнему говорится, что NSMetaDataQuery не функционирует должным образом. Крайне неприятно, что iCloud все еще не работает должным образом, но, к сожалению, мы ничего не можем сделать.

Эта проблема все еще сохраняется. Я смог проследить его до следующего расхождения:

  • Если вы ограничиваете предикат поиска в запросе ключом name,

Например

[NSPredicate predicateWithFormat:@"%K like[cd] %@", NSMetadataItemFSNameKey, @"*"]

Тогда он будет работать, как и ожидалось (размещение всех четырех уведомлений жизненного цикла запроса).

  • Если, однако, вы попробуете либо составной предикат, либо попытаться работать с путем,

Как в

[NSPredicate predicateWithFormat:@"%K BEGINSWITH %@", NSMetadataItemPathKey, [self cloudDocumentsURL].path]

Или

[NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:namePred, pathPred, nil]];

Тогда только первоначальное уведомление будет опубликовано.

За последний год я перепробовал буквально сотни комбинаций этих настраиваемых переменных в нескольких тестовых и предназначенных для производства приложениях и до сих пор не нашел контрпримера к этой гипотезе.

К сожалению, NSMetadataQuery просто не работает для вездесущих магазинов (по состоянию на 10.8).

Мой обходной путь состоит в том, чтобы получить необработанные результаты из запроса и работать в основном на связанном NSArrayController, который может фильтровать свои результаты. Этот будет означать рефакторинг от запроса.результаты для большинства существующих кодов и есть хит производительности (предположительно), но это единственный способ, который я нашел. Мне бы очень хотелось иметь альтернативу.