Архитектура и производительность UIDocument и NSFileWrapper

Недавно мы преобразовали наш код для использования UIDocument вместо непосредственного управления файлами в файловой системе, и в результате мы столкнулись с некоторыми проблемами производительности. Нам интересно, неправильно ли мы используем этот класс, были ли у кого-то еще такие проблемы и каковы общие способы их решения.

Наше приложение

У нас есть «приложение для обуви», которое управляет кучей документов, каждый из которых состоит из нескольких файлов изображений, которые могут быть довольно тяжелыми, небольшого файла метаданных и небольшого изображения для предварительного просмотра. Пользователь может иметь много документов на своем устройстве (более 1000 документов). Файлы каждого документа сгруппированы в каталоге, и мы используем NSFileWrapper для их чтения и записи.

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

Чтобы получить эту информацию, мы открываем все документы, читаем их метаданные и предварительно просматриваем изображение, если это необходимо, закрываем их, а затем снова открываем по требованию.

Проблема №1: Медленная загрузка

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

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

Проблема № 2: многопоточность

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

Мы решили эту проблему, синхронизировав открытые операции с помощью семафора. Недостаток этого подхода в том, что он еще больше замедляет загрузку.

Вопросы

  1. Есть ли какая-то фундаментальная проблема в том, как мы используем UIDocument? Если не:
  2. Кто-нибудь сталкивался с подобной проблемой времени загрузки? Каков общий способ ее решения? Сохраняют ли другие приложения индексный файл?
  3. Есть ли способ заставить документ пользовательского интерфейса использовать пул потоков? Если нет, то как вы контролируете использование ресурсов?

Спасибо!


person Hila    schedule 24.04.2014    source источник
comment
Вы когда-нибудь находили решение? Я сталкиваюсь с теми же проблемами со многими UIDocuments, которые содержат несколько больших видеофайлов. Я думаю о том, чтобы вообще отказаться от UIDocument или сохранить отдельный индексный файл. Может быть, вы приобрели некоторые идеи по этому поводу?   -  person Rengers    schedule 05.06.2014
comment
@Rengers Пожалуйста, смотрите мой ответ ниже. К сожалению, у меня нет для вас хороших новостей.   -  person Hila    schedule 06.06.2014


Ответы (3)


Хорошо, здесь нет хороших новостей.

Мы пытались проконсультироваться с друзьями в отрасли, профилировать UIDocument и использовать его модифицированные реализации, которые изменяют различные аспекты его работы, чтобы посмотреть, можем ли мы улучшить его производительность, но безрезультатно.

Мой вывод состоит в том, что UIDocument не подходит для такого использования — он просто не предназначен для поддержки требований к задержке и пропускной способности, которые мы предъявляем к открытым операциям. UIDocument следует использовать только тогда, когда вы хотите открыть небольшое количество файлов в любой момент (так же, как текстовые процессоры и приложения для рисования). По общему признанию, это именно то, что говорится в документации Apple, но я думаю, нам пришлось узнать, насколько они серьезны, на собственном горьком опыте :)

В итоге мы использовали некоторые «трюки» для улучшения взаимодействия с пользователем и отойдем от UIDocument, как только сможем.

Поэтому моя рекомендация заключается в том, что только если:

  1. Ваше приложение по своей природе напоминает приложение, основанное на документах, а это означает, что в любой момент у вас будет открыто не более нескольких документов.
  2. Вам не нужна информация внутри документов, чтобы «обнаружить» их и показать пользователю, или вы можете позволить себе накладные расходы на управление отдельным индексным файлом.
  3. Вам действительно нужны возможности автоматического сохранения/отмены/синхронизации/iCloud этого класса.

затем используйте его. В противном случае рассмотрите другие решения.

Дополнительное примечание, которое не имеет прямого отношения к вопросу, но я добавлю здесь как общедоступную услугу: асинхронная модель UIDocument потребовала некоторых серьезных изменений в архитектуре приложения, когда мы перешли от прямого доступа к файлам. Если вы планируете сделать этот шаг, тщательно оцените работу, которую вам нужно будет сделать.

Удачи будущие программисты.

person Hila    schedule 05.06.2014
comment
Хила, спасибо за это расширенное продолжение! Я профилировал сохранение и загрузку с помощью NSFileWrappers. Кажется, NSFileWrapper действительно загружает все данные в оперативную память, что делает его непригодным для больших файлов. Теперь я все больше убеждаюсь отказаться от UIDocument и разработать собственное решение, поддерживающее метаданные и большие файлы. Еще один вариант, о котором я думал, это переопределение saveToURL:forSaveOperation:completionHandler. Включены ли в ваши оптимизации это? - person Rengers; 06.06.2014
comment
@Rengers Мы также подозревали NSFileWrapper, но, насколько я знаю, он выполняет отображение памяти, которое не должно быть таким плохим, как чтение всех данных в память (хотя я могу ошибаться). Мы проверили его действие, заменив наш базовый класс UIDocument модифицированным классом, использующим реализацию, которая считывает данные по запросу, но это не сильно улучшило нашу производительность. Мы также создали тестовое приложение, которое открывало кучу очень маленьких файлов, и производительность тоже была низкой. Я не помню, какие методы мы пытались изменить. - person Hila; 06.06.2014
comment
@Rengers Я подозреваю, что виновата модель потоков, но у меня не было времени проверить это, потому что в какой-то момент нам пришлось сократить наши потери и двигаться дальше. Надеюсь это поможет :) - person Hila; 06.06.2014
comment
Это действительно помогает, похоже, я в той же лодке, что и вы, ребята, некоторое время назад :). Я, вероятно, переключусь на индивидуальный дизайн, услышав это. Сохранение действительно больших файлов в iCloud в любом случае невозможно, а отдельное хранение метаданных как бы побеждает плюсы автономных документов. Спасибо еще раз! - person Rengers; 06.06.2014

Классы документов имеют методы для асинхронного чтения. Вы пробовали это?

person Joel    schedule 23.01.2015

Это действительно звучит как что-то более подходящее для Core Data или SQLite для метаданных. По крайней мере, кэшируйте метаданные в Core Data (одно хранилище для всего приложения, а не по одному для каждого документа).

person Rick    schedule 25.06.2016