NSUndoManager приведение сбоя NSUndoManagerProxy в коде Swift

В нашем приложении мы используем следующий код:

let lInvocationTarget = lUndoManager.prepare(withInvocationTarget: self)
let _ = (lInvocationTarget as! MyObjectType).myMethod(_: self.opacity, undoManager: lUndoManager)

Он компилируется без предупреждений и работает нормально под macOS 10.12 Sierra. Однако он вылетает во время выполнения 10.9 - 10.11 (Маверикс до Эль-Капитана). Уведомление о сбое:

Не удалось преобразовать значение типа "NSUndoManagerProxy" (0x7fff76d6d9e8) в "MyObjectType" (0x108b82218).

Затем я переписал код:

if let lInvocationTarget = lUndoManager.prepare(withInvocationTarget: self) as? MyObjectType {
    let _ = lInvocationTarget.setOpacity(_: self.opacity, undoManager: lUndoManager)
}

Тогда это не падает, но тогда Отмена вообще не работает. Этот последний способ написания взят непосредственно из документации Apple, поэтому, очевидно, поведение изменилось в Swift 3 или 10.12 SDK. Я использую Xcode 8.2 с Swift 3 и SDK 10.12

RegisterUndo(withTarget, selector:, object:) не подходит, потому что у меня есть много других отменяемых методов с большим количеством аргументов. На самом деле не хочу, чтобы обернуть их в словарь или так. И даже когда селекторы в настоящее время довольно безопасны, они все равно мне не нравятся. Существует также API на основе блоков (registerUndo(withTarget: handler:)), но это, к сожалению, только для 10.11+.

Кто-нибудь сталкивался с такой же проблемой? И еще важнее: кто-нибудь придумал выход?

2 ответа

Решение

Я так удивлен, что слышу, как ваш первый код работает на macOS 10.12. Метод prepare(withInvocationTarget:) была вещь, которая вряд ли работает в Swift. Не только возвращаемый прокси-объект не является экземпляром исходного класса, но и не является потомком объекта. NSObject (в аренде в некоторых бывших OS Xs).

В любом случае, это стоит попробовать

let lInvocationTarget = lUndoManager.prepare(withInvocationTarget: self)
_ = (lInvocationTarget as AnyObject).myMethod(self.opacity, undoManager: lUndoManager)

Я обнаружил, что registerUndoWithTarget:handler: сейчас лучший API.

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