Отмена ввода данных Core Data, которые выполняются из основного потока
Я работаю над кодом, который использует NSOperation
для импорта данных. Я хотел бы, чтобы пользователь мог отменить экземпляры NSManagedObject
, созданные во время операции импорта.
Из того, что я могу сказать, невозможно использовать NSManagedObjectContext
-undoManager
для любых операций, выполняемых с основного потока. Из раздела "Руководство по программированию основных данных" в разделе "Использование ограничения потока для поддержки Concurrency" мы имеем следующие два условия:
- Необходимо передать только идентификатор объекта между контекстами управляемого объекта (on отдельные потоки)
- Управляемые объекты должны быть сохранены в контексте до можно использовать идентификатор объекта.
Это имеет смысл, поскольку управляемые объекты необходимо перенести из частного хранилища (NSManagedObjectContext
) в общедоступное хранилище (NSPersistentStore
), прежде чем их можно будет использовать.
К сожалению, сообщение -save:
также вызывает удаление любых управляемых объектов в стеке отмены. Из раздела "Управление памятью с использованием основных данных" одного и того же руководства:
Управляемые объекты, которые находятся на рассмотрении изменения (вставки, удаления или обновления) сохраняются по их контексту пока их контекст не будет отправлен save:, reset, откат или сообщение dealloc, или соответствующее количество отменить отмените изменение.
Я пробовал несколько вещей, чтобы обойти это ограничение, и все в конечном итоге приводит к большей части работы, происходящей на основной теме (и вращающихся шаров для пляжа). Любые подсказки к отмене работы с объектами, созданными из основного потока будет очень признателен.
-
Был представлен расширенный радар: rdar://проблема/8977725
Ответы
Ответ 1
Этот ответ, вероятно, будет немного назад и вперед. Если я правильно понял проблему, вы делаете импорт, но когда импорт сделан, вы хотите, чтобы пользователь мог выбрать, что будет сохранено из импорта?
Если это неверно, исправьте мои предположения, и я обновлю этот ответ.
Если это правильно, то что вы можете сделать:
Поскольку эти объекты не являются частью NSManagedObjectContext
, но они существуют только в памяти и должны быть потокобезопасными, поскольку они еще не привязаны к NSManagedObjectContext
.
Это, конечно, теоретически и потребует тестирования. Однако он должен выполнить вашу задачу.
Ответ 2
Не эксперт, но я думаю, что вам нужно будет создать второй контекст для выполнения операций, а затем объединить два контекста вместе. Вы должны иметь возможность управлять слиянием как шаг отмены. Обратите внимание, что это работает только в том случае, если вы обрабатываете весь набор операций как один шаг отмены, насколько это касается пользователя.
Ответ 3
Предположим, что вы используете отдельный контекст для фонового потока, и как только это делается, нажимайте [[backgroundContext undoManager] undo]
на стеке отмены нити переднего плана? Я никогда не пробовал ничего подобного, но с головы до головы я не могу думать о причине, по которой он не должен работать.
Ответ 4
Один из вариантов может заключаться в том, чтобы сделать поток импорта постоянным. Даже когда поток завершен, он переходит в состояние бездействия. Таким образом, ваш threaded ManagedObjectContext сохраняется в соответствующем потоке. Затем, когда пользователь хочет отменить изменение, отправьте сообщение в поток, чтобы использовать нестационар.
Ответ 5
Невероятно вероятно, что вы это рассмотрели, и вы, скорее всего, будете искать решение, используя существующий undoManager
, но на всякий случай:
Поскольку вы вставляете объекты и не обновляете существующие, у вас есть возможность пометить их идентификатором транзакции, поскольку каждая партия импортируется, удаляя их в фоновом потоке в случае отмены. Для тега достаточно простого приращения NSNumber
.
Неэлегантный, но работоспособный.