更改 CALayer 属性:EXC_BAD_INSTRUCTION

use*_*809 2 cocoa core-animation

我试图通过单击子层来实现子层的选择,并可视化它已被选择,例如通过更改子层的背景颜色。但是,无论如何,我最终都会遇到以下错误,但是我尝试更改任何属性:

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
Run Code Online (Sandbox Code Playgroud)

她是我的函数,是从我的NSView子类mouseUp函数中调用的。

func SelectObject( atPoint: NSPoint)
{
    let thePoint = atPoint as CGPoint
    if let hitLayer = itsCourseLayer.hitTest( thePoint) {
        if (hitLayer != itsCourseLayer) {
            // Gives following error:
            // Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
            hitLayer.backgroundColor = NSColor.red.cgColor 
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我也尝试过hitLayer.setValue( NSColor.red.cgColor, forKeyPath: "backgroundColor")并且我尝试用CATransaction.begin()CATransaction.commit()包围它包围它,或者更改该属性的任何其他属性子层。但没有成功。

知道我的代码有什么问题吗?

rob*_*off 5

错误消息告诉您一种解决方案:init(layer:)CPCoursePointLayer.

当您在图层上设置属性时,并且该图层位于非隐藏窗口的图层树中,核心动画会CAAction通过向该图层发送消息来查找该actionForKey:属性。如果该搜索返回nil,Core Animation 会使用一些默认参数为该属性创建隐式动画。

任何带有附加动画的层都有相应的表示层。(阅读“层树反映动画状态的不同方面”以获取更多信息。)因此 Core Animation 需要为您的hitLayer. 它使用类init(layer:)上的初始化程序来执行此操作CPCoursePointLayer

在 Swift 中,类不会自动继承其超类的所有构造函数,因此您的CPCoursePointLayer类没有该初始值设定项。所以你的应用程序崩溃了。

一种解决方案是将init(layer:)初始化程序添加到您的CPCoursePointLayer类中:

init(layer: CALayer) {
    let layer = layer as! CPCoursePointLayer
    // copy any custom properties from layer to self here
    super.init(layer: layer)
}
Run Code Online (Sandbox Code Playgroud)

如果定义init(layer:),则可以对图层的属性进行动画处理,并允许它们隐式进行动画处理。

如果您从不打算显式或隐式地为图层的属性设置动画,那么您可以通过NSNull在 Core Animation 搜索操作时返回来禁用隐式动画,例如通过将此方法添加到您的CPCoursePointLayer类中:

override class func defaultAction(forKey key: String) -> CAAction? {
    return unsafeBitCast(NSNull(), to: CAAction?.self)
}
Run Code Online (Sandbox Code Playgroud)