Отмена вставки основных данных, выполняемых из основного потока - PullRequest
15 голосов
/ 09 февраля 2011

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

Из того, что я могу сказать, невозможно использовать NSManagedObjectContext -undoManager для любых операций, выполняемых вне основного потока. Из раздела Руководство по программированию базовых данных в Использование ограничения потока для поддержки параллелизма , у нас есть два условия:

  1. Должен быть передан только objectID между контекстами управляемого объекта (на отдельные темы)
  2. Управляемые объекты должны быть сохранены в контексте перед можно использовать идентификатор объекта.

Это имеет смысл, поскольку управляемые объекты необходимо переместить из частного хранилища (NSManagedObjectContext) в общедоступное хранилище (NSPersistentStore), прежде чем их можно будет совместно использовать.

К сожалению, сообщение -save: также приводит к удалению любых управляемых объектов в стеке отмены. Из раздела Управление памятью с использованием базовых данных раздела того же руководства:

Управляемые объекты с ожидающими изменения (вставки, удаления или обновления) сохраняются в их контексте пока их контекст не будет отправлен сохранить :, сбросить, откатить или вернуть сообщение, или соответствующее количество отмен, чтобы отменить изменение.

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

-

Передан радар улучшения: rdar: // problem / 8977725

Ответы [ 5 ]

2 голосов
/ 10 февраля 2011

Этот ответ, вероятно, будет немного назад и вперед.Если я правильно понимаю проблему, вы выполняете импорт, но когда импорт завершен, вы хотите, чтобы пользователь мог выбрать, что будет сохранено из импорта?

Если это не так, пожалуйста, исправьте мои предположенияи я обновлю этот ответ.

Если он верный, то вы можете сделать следующее:

  1. Изменить создание фонового объекта на

    NSEntityDescription *myEntity = ... //Entity from your context
    [[NSManagedObject alloc] initWithEntity:myEntity
             insertIntoManagedObjectContext:nil];
    
  2. Храните эти сущности в массиве.
  3. Передайте сущности обратно в основной поток по мере необходимости.
  4. Освободите любые объекты, которые вы не хотите сохранять
  5. Позвоните [myMainContext insertObject:managedObject] на любой объект, который вы хотите сохранить.
  6. Выполните сохранение на NSManagedObjectContext.

Поскольку эти объекты не являются частью NSManagedObjectContext, но они толькосуществуют в памяти и должны быть поточно-ориентированными, поскольку они еще не привязаны к NSManagedObjectContext.

Это, конечно, теоретически и потребует тестирования.Однако это должно достичь вашей цели.

0 голосов
/ 10 февраля 2011

Очень вероятно, что вы рассмотрели это, и вы, вероятно, ищете только решение, использующее существующее undoManager, но на всякий случай:

Поскольку вы вставляете объекты, а не обновляете существующиеу вас есть возможность пометить их идентификатором транзакции при импорте каждого пакета, удалив их в фоновом потоке в случае отмены.Для тега достаточно простого приращения NSNumber.

Не элегантный, но выполнимый.

0 голосов
/ 09 февраля 2011

Предположим, что вы используете отдельный контекст для фонового потока, и как только это будет сделано, вставьте [[backgroundContext undoManager] undo] в стек отмены потока переднего плана?Я никогда не пробовал ничего подобного, но изо всех сил не могу придумать причину, по которой это не должно работать.

0 голосов
/ 09 февраля 2011

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

0 голосов
/ 09 февраля 2011

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

...