I'm trying to implement selection of a subLayer by clicking on it and visualize that it is had been selected by for example changing the background color of the subLayer. However, I end up with the following error whatever and however I attempt to change any property:
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
Her is my function that is called from my NSView
sub class' mouseUp
function.
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
}
}
}
I've also tried hitLayer.setValue( NSColor.red.cgColor, forKeyPath: "backgroundColor") and I've tried to surround it with CATransaction.begin() and CATransaction.commit(), or to change any other property of the subLayer. But with no success.
Any Idea what is wrong with my code?
The error message is kind of telling you one solution: implement init(layer:)
in CPCoursePointLayer
.
When you set a property on a layer, and that layer is in a non-hidden window's layer tree, Core Animation looks for a CAAction
for that property, by sending the actionForKey:
message to the layer. If that search returns nil
, Core Animation creates an implicit animation for the property using some default parameters.
Any layer with an attached animation has a corresponding presentation layer. (Read Layer Trees Reflect Different Aspects of the Animation State for more info.) So Core Animation needs to create the corresponding presentation layer for your hitLayer
. It does this using the init(layer:)
initializer on your CPCoursePointLayer
class.
In Swift, a class doesn't automatically inherit all of its superclass's constructors, so your CPCoursePointLayer
class doesn't have that initializer. So your app crashes.
One solution is to add the init(layer:)
initializer to your CPCoursePointLayer
class:
init(layer: CALayer) {
let layer = layer as! CPCoursePointLayer
// copy any custom properties from layer to self here
super.init(layer: layer)
}
If you define init(layer:)
, then you can animate properties of your layer, and allow them to be implicitly animated.
If you never plan to explicitly or implicitly animate properties of your layer, then you can instead disable implicit animations by returning NSNull
when Core Animation searches for an action, for example by adding this method to your CPCoursePointLayer
class:
override class func defaultAction(forKey key: String) -> CAAction? {
return unsafeBitCast(NSNull(), to: CAAction?.self)
}