Правильный способ обнаружения удаления документов в iCloud на разных устройствах?

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

На устройстве 1: когда я удаляю документ, я вызываю

        [fileCoordinator coordinateWritingItemAtURL:fileURL options:NSFileCoordinatorWritingForDeleting
          error:&err byAccessor:^(NSURL* writingURL) {
             [fileManager removeItemAtURL:writingURL error:nil];

Это отлично работает на Device1, все остается синхронизированным. На устройстве 2: я пытался полагаться на уведомления NSMetadataQuery:

Исходный список файлов поступает нормально на NSMetadataQueryDidFinishGatheringNotification Добавление/изменение документа проходит нормально через NSMetadataQueryDidUpdateNotification

Когда я удаляю файл на Устройстве 1, я получаю странный результат: приходит обновление NSMetadataQueryDidUpdateNotification со всеми моими документами (кроме удаленного) в списке. Я не уверен, как я должен определить, что отсутствующий файл был удален или что уведомление об обновлении было для этой цели

Вопрос 1. Что следует проверять?

Я попробовал другой маршрут, который должен был зарегистрироваться как NSFilePresenter для URL-адреса iCloud:

- (NSURL *)iCloudDocumentsURL
{
    return [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil] URLByAppendingPathComponent:@"Documents"];
}

Теперь меня вызывают по протоколу NSFilePresenter, когда файлы в этом URL-адресе изменяются, но логика для определения отсутствующего документа карательно медленная, поскольку обратный вызов нечеткий. Единственный ответ, который я получаю, это - (void)presentedItemDidChange;. Я ожидал получить обратный вызов через - (void)accommodatePresentedSubitemDeletionAtURL:(NSURL *)url completionHandler:(void (^)(NSError *errorOrNil))completionHandler, но этот метод никогда не вызывается.

Вопрос 2. Есть идеи, как заставить это работать?


person ski_squaw    schedule 02.05.2012    source источник


Ответы (3)


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

Это то, что я делаю в своем контроллере представления «файловый менеджер», потому что я храню NSMutableDictionary записей файлов, который включает, среди прочего, ключи для позиций «значков» файлов в моем главном представлении. Когда я получаю уведомление об обновлении, и это обновление приводит к большему или меньшему количеству файлов, я анимирую изменения значков на основе этих изменений файлов.

person tobinjim    schedule 15.06.2012
comment
Таким образом, вы не знаете, когда файлы перемещаются. Если вам все равно и вы храните метаданные в пакете файлов, это нормально, но если вы ссылаетесь на файлы извне, то этот подход не даст хороших результатов. - person Ben Affleck; 24.12.2015

tobinjim прав в том, что NSMetadataQuery каждый раз возвращает весь набор результатов. Я ожидал, что будут отправлены только изменения для экономии полосы пропускания, но я не правильно выполнил RTFM.

Как только я это понял, я столкнулся с ошибкой в ​​библиотеках iOS. Это был сбой, который произошел, когда я удалил документ на одном устройстве, а обновление запроса iCloud появилось на другом моем устройстве:

    2012-06-25 13:15:12.343 app[19779:707] *** -[NSMutableIndexSet indexGreaterThanOrEqualToIndex:]: message sent to deallocated instance 0xdaae2c0
    (gdb) bt
    #0  0x31937870 in ___forwarding___ ()
    #1  0x31892650 in __forwarding_prep_0___ ()
    #2  0x373cc676 in __NSIndexSetEnumerate ()
    #3  0x373a1ee8 in -[NSIndexSet enumerateIndexesWithOptions:usingBlock:] ()
    #4  0x371c1f08 in -[LBQuery _processUpdates] ()
    #5  0x373571a6 in -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:modes:] ()
    #6  0x3737ffa4 in -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:] ()
    #7  0x371c2274 in -[LBQuery processUpdates] ()
    #8  0x373a88d6 in -[NSMetadataQuery _update] ()

Я считаю, что нашел причину этой проблемы. Я просматривал пример нового кода IOS 6 из презентации Люка Хистермана. Я заметил, что не было вызовов NSMetadataQuery для отключения/включения обновлений, как это было в предыдущих примерах приложений iCloud. Я удалил все обращения к ним. Я также изменил свой метод, который обрабатывал вызовы NSMetadataQueryDidUpdateNotification, чтобы они выполнялись асинхронно, но в порядке очереди.

Кажется, между потоками для NSMetadataQuery возникает состояние гонки. В некоторых вызовах результаты запроса в порядке, но в других случаях они были выпущены, и результаты отображаются как NSZombie (благодаря gdb, который намного лучше, чем текущий lldb). Таким образом, включение и отключение запроса между потоками приводит к сбою LBQuery из-за вызова освобожденных объектов.

Удаление всех включений и отключений для NSMetadataQuery, похоже, также ускорило мое приложение, и iCloud кажется намного более стабильным.

person ski_squaw    schedule 25.06.2012
comment
Действительно интересно. Вы теперь удаляете себя как наблюдателя NSMetaDataQueryDidFinishGatheringNotification, чтобы остановить прерывания так же, как остановил запрос? - person tobinjim; 29.06.2012
comment
Я не. Мой метод обратного вызова запускает асинхронную обработку, поэтому основной поток не замедляется. Мне пришлось добавить несколько блоков @synchronized вокруг переменных, которые могут быть изменены более чем одним асинхронным потоком. Теперь стабильно и быстро, без сбоев - person ski_squaw; 29.06.2012

Начиная с iOS 8 NSMetadataQuery расширил NSMetadataQueryDidUpdateNotification userInfo с помощью NSMetadataQueryUpdateRemovedItemsKey, который можно использовать для определения того, какие файлы были удалены.

https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSMetadataQuery_Class/#//apple_ref/doc/constant_group/Keys_for_Use_with_a_Notification_Info_Dictionary

person Ben Affleck    schedule 27.12.2015