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

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

TouchesBegan method...
dispatch_async(dispatch_get_main_queue(), ^{
    [self saveCurrentState];
});

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

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

Как я могу это решить? Как лучше всего это сделать?

Благодарю.


person Duck    schedule 10.06.2011    source источник


Ответы (2)


Нужно ли сохранять изображение на диск каждый раз, когда оно редактируется? Может быть, вы могли бы сделать резервную копию действий пользователя и сохранить ТЕ. Что-то вроде:

Line(12, 24, 500, 24)
person Nick ODell    schedule 10.06.2011
comment
Чтобы добавить, я не уверен, что сохранение рисунка на изображении - правильный путь. Вы потеряете гибкость отмены и повторения действий, что, как мне кажется, является ключевым компонентом, когда дело доходит до рисования (по крайней мере, на устройствах!). Было бы разумно, чтобы работа сохранялась в путях, а не в изображении. Это даст вам возможность воссоздавать изображение, когда вы вернетесь, отменять и повторять действия, и, что более важно, сохранение его на заднем плане не доставит особых хлопот. - person Deepak Danduprolu; 11.06.2011
comment
проблема сохранить его в путях из-за этого: мое приложение предлагает 50 уровней UNDO / REDO. Предположим, я на последнем уровне. Затем пользователь нажимает ОТМЕНИТЬ. Затем приложение должно начать рисовать с нуля до шага 49, чтобы воссоздать то, что у нас было тогда. Если вы представляете, что каждый путь состоит из 50–100 точек, это требует большой работы, поэтому отмена может занять много времени. Тем более, что все рисуется в цикле drawRect. При использовании изображений UNDO занимает 0,1 секунды, но у меня есть эта раздражающая проблема с задержкой. - person Duck; 11.06.2011
comment
Вы сохраняете изображения после каждого действия пользователя? - person Deepak Danduprolu; 11.06.2011
comment
Я тестирую несколько возможностей. В текущем тесте я делаю это для каждого ToucheBegan. Это одно сохраненное изображение за цикл рисования. Для этого я запускаю очередь GCD, но она сильно отстает, и я готов изменить ее на любой другой метод, который работает лучше. - person Duck; 11.06.2011
comment
Отслеживайте, какие операции изменили какие пиксели. Предположим, что кнопка отмены нажата, и вы хотите отменить строку. Просто пересчитайте участок экрана, которого коснулась линия. Большинство операций не коснутся области, которую вы хотите пересчитать. Вероятно, вам придется пересчитать только 10 операций или около того. Во-вторых, вы можете каждый раз создавать резервные копии действий пользователя и просто сохранять изображение каждые 10 операций. В качестве альтернативы, вместо того, чтобы сохранять все изображение каждые 10 шагов, вы можете просто сохранять области, которые требуют наибольшего пересчета. - person Nick ODell; 11.06.2011
comment
Я проверял эту идею в прошлом, но чтение этого снова дало другие идеи переписать метод рисования и хранения с использованием путей, поэтому я воссоздал все это, и теперь это молниеносно. Файлы больше не сохраняются на диск. Спасибо всем вам, ребята, и другим, кто прокомментировал другие ответы. - person Duck; 11.06.2011
comment
Чтобы добавить к тому, что сказал Ник, обычно шаблон отмены состоит из сохранения операции в стеке. Но вместо сохранения я нарисовал линию цвета x, то, что вы сохраняете, — это негативное действие того, что сделал пользователь, например, мне нужно нарисовать линию цвета Y, чтобы вернуться в предыдущее состояние. Возврат к истории отмены возвращает изображение и создает отрицательный буфер повторения для пользователя. Конечно, для некоторых действий вам потребуется хранить большие куски или весь экран из-за их характера, но большинство операций рисования будут легкими. - person Grzegorz Adam Hankiewicz; 11.06.2011

Один из способов импровизации — использование плитки. Таким образом, в каждый момент вы сохраняете только плитки, которые изменились с момента последней записи. Таким образом, вы не будете писать больше, чем необходимо, и, вероятно, уменьшите объем записываемых данных, поскольку пользователь вряд ли заполнит большую часть чертежной доски.

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

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

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

person Deepak Danduprolu    schedule 10.06.2011
comment
да, мне нравится эта идея с тайлами, но я не вижу именно того, что вы называете тайлами. Что вы имеете в виду, когда говорите о создании плитки? Есть способ проверить координату пальца по массиву прямоугольников или что-то еще? - person Duck; 11.06.2011