【问题标题】:NSUndoManager casting NSUndoManagerProxy crash in Swift codeNSUndoManager 在 Swift 代码中强制转换 NSUndoManagerProxy 崩溃
【发布时间】:2016-12-19 10:41:53
【问题描述】:

在我们的应用程序中,我们使用以下代码:

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

编译时没有警告,并且在 macOS 10.12 Sierra 下运行良好。然而,它在 10.9 - 10.11(小牛直到 El Capitan)的运行时崩溃。 崩溃报告通知:

无法将“NSUndoManagerProxy”(0x7fff76d6d9e8) 类型的值转换为“MyObjectType”(0x108b82218)。

然后我将代码重写为:

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

然后它不会崩溃,但是撤消根本不起作用。 最后一种写法直接来自Apples documentation,因此在 Swift 3 或 10.12 SDK 中行为显然发生了变化。我将 Xcode 8.2 与 Swift 3 和 SDK 10.12 一起使用

registerUndo(withTarget, selector:, object:) 不合适,因为我有很多其他带有更多参数的可撤消方法。真的不想把它们包装在字典里。即使现在选择器是相当安全的类型,我仍然不喜欢它们。 还有基于块的 API (registerUndo(withTarget: handler:) ),但不幸的是,这仅适用于 10.11+。

有人遇到过同样的问题吗?更重要的是:有人想出出路吗?

【问题讨论】:

    标签: swift macos nsundomanager


    【解决方案1】:

    听到您的第一个代码在 macOS 10.12 上运行,我感到非常惊讶。 prepare(withInvocationTarget:) 方法一直是 this-hardly-works-in-Swift 的事情。不仅返回的代理对象不是原始类的实例,而且该对象也不是NSObject 的后代(至少在某些以前的 OS X 中)。

    无论如何,这是一件值得尝试的事情:

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

    【讨论】:

    • 我也很惊讶转换为 AnyObject 编译:-)。确实期望在 AnyObject 上调用未知方法的编译器警告。但我可以确认您的解决方案有效!
    • 我可以确认这个解决方案也适用于我(虽然我想知道为什么首先会出现错误),但我想补充一点,我还需要将 MyObjectType 声明为NSObject。仅声明 class MyObjectType {...} 将导致编译错误“'AnyObject' 类型的值没有成员 'myMethod'”。
    【解决方案2】:

    我发现 registerUndoWithTarget:handler: 现在是一个更好的 API。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-01-27
      • 2015-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多