Основные данные: отключить отмену для определенных атрибутов. Рекомендуемый подход не работает

У меня есть текстовое поле и флажок, подкрепленные основными данными. Изменения в флажке должны быть исключены из любых операций отмены / возврата.

Рекомендуемый подход (найденный при переполнении стека) - следующий фрагмент.

@IBAction func stateDidChange(sender: NSButton?)
{
    //disable undo manager
    context.processPendingChanges()
    context.undoManager?.disableUndoRegistration()

   //set value
   let value = Bool(sender!.state == NSOnState)
   <some NSManagedObject>.flag = value

    //enable undo manager
    context.processPendingChanges()
    context.undoManager?.enableUndoRegistration()
 }

Но это не работает. Когда пользователь

  1. редактирует текстовое поле,
  2. обновляет флажок,
  3. и продолжает редактировать текстовое поле,

затем изменения в флажке включаются в действие отмены.

Я тоже пробовал

     NSNotificationCenter.defaultCenter().postNotificationName(NSUndoManagerCheckpointNotification, object: self.undoManager)
    self.undoManager?.disableUndoRegistration()
    //do work
    NSNotificationCenter.defaultCenter().postNotificationName(NSUndoManagerCheckpointNotification, object: self.undoManager)
    self.undoManager?.enableUndoRegistration()

Я даже попробовал это в подклассе NSManagedObject

    var flag : Bool {
    get {
        self.willAccessValueForKey("flag")
        let text = self.primitiveValueForKey("flag") as! Bool
        self.didAccessValueForKey("flag")
        return text
    }
    set {
        let context = self.managedObjectContext!
        context.processPendingChanges()
        context.undoManager?.disableUndoRegistration()

        self.willChangeValueForKey("flag")
        self.setPrimitiveValue(newValue, forKey: "flag")
        self.didChangeValueForKey("flag")

        context.processPendingChanges()
        context.undoManager?.enableUndoRegistration()

    }
}

1 ответ

Решение

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

Тем не мение...

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

Рассмотрим объект с меткой = A и флажком = NO. Установите метку на B с разрешенной отменой. Состояние сейчас B & NO. Это можно откатить до A & NO. Теперь установите флажок ДА без отмены. Штат сейчас B & YES. Если отменить вызов сейчас, желаемое состояние будет A & YES, но это состояние никогда не существовало. Стек состояний для записанного

B & YES <- текущее состояние

B & NO - A & NO <- стек LIFO прошлых состояний

Однако, как я уже сказал, я на самом деле не проверял это. Некоторое время назад я провел несколько неубедительных тестов с хранилищем XML coreData, которое показало, что есть нечто большее, чем это. С другой стороны, я могу представить, что это может быть правдой для хранилища с резервированием SQLite, в зависимости от того, как CoreData использует базовую структуру SQL. Должен быть проверен.

Если это так, то можно предположить, что он реализован на объектной основе и что его можно обойти, поместив неотменяемые действия в дочерний объект один на один. Таким образом, состояние основного объекта остается непротиворечивым, в примере метка и ссылка на checkBoxObject. Тогда внутреннее состояние этого checkBoxObject может не иметь значения, так как ссылка в главном объекте неизменна. Но это должно быть проверено.

ОБНОВЛЕНИЕ В дополнение к моему первоначальному ответу, я потратил время на проверку представленной гипотезы и нашел ее верной. Похоже, что CoreData реализует отмену в виде LIFO-стека полных состояний объекта. Таким образом, невозможно иметь выборочную отмену определенных свойств внутри одного объекта.

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

Поведение идентично как для хранилищ CoreData с XML и SQLite.

Я также обнаружил, что для получения желаемого поведения код, модифицирующий свойства coreData, должен быть заключен в группу отмены, и что -processPendingChanges должен вызываться в контексте управляемого объекта до закрытия группы отмены.

Другие вопросы по тегам