Reputation: 17170
I have a swift custom CALayer that has a few dynamic (actually @NSManaged
properties) I have everything set up correctly and the layers actionForKey is being called.
override public func actionForKey(key: String!) -> CAAction! {
switch key {
case "maxCircles", "numCircles":
let animation = CABasicAnimation(keyPath: key)
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear);
animation.fromValue = self.presentationLayer().valueForKey(key);
animation.duration = 0.2
return animation;
default:
return super.actionForKey(key)
}
}
Sometimes self.presentationLayer().
throws an exception because it is implicitly unwrapped and is nil. In objective-C the code normally just does:
[[self presentationLayer] valueForKey:key]
Which doesn't crash but I never actually realised it could call though nil and generate 0 - which feels very wrong to me. There's no guarantee I'm animating from nil.
What's the right way to access presentationLayer
in Swift? Should I test for nil? i.e.:
override public func actionForKey(key: String!) -> CAAction! {
if ( key == "maxCircles" || key == "numCircles" ) && self.presentationLayer() != nil {
let animation = CABasicAnimation(keyPath: key)
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear);
animation.fromValue = self.presentationLayer().valueForKey(key);
animation.duration = 0.2
return animation;
}
return super.actionForKey(key)
}
Upvotes: 2
Views: 2057
Reputation: 66242
Matt Long's solution works. If you'd like to keep the switch
syntax, though, you can just test for nil
using the case … where
syntax:
override func actionForKey(key: String!) -> CAAction! {
switch key {
case "maxCircles", "numCircles" where self.presentationLayer() != nil:
let animation = CABasicAnimation(keyPath: key)
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear);
animation.fromValue = self.presentationLayer().valueForKey(key);
animation.duration = 0.2
return animation;
default:
return super.actionForKey(key)
}
}
Alternatively, you could just provide a default fromValue
if there's no presentation layer:
animation.fromValue = self.presentationLayer() != nil ? self.presentationLayer().valueForKey(key) : 0;
Upvotes: 1
Reputation: 24466
The presentationLayer
property returns an optional, so yes you should test for nil. In Objective-C messaging nil is a no-op and therefore won't cause your app to crash. Remember that safety is one of the primary goals of swift, so you will need to do your own checking here. If you write your function like this, it will work similarly to the Objective-C counterpart:
override public func actionForKey(key: String!) -> CAAction! {
if key == "maxCircles" || key == "numCircles" {
// Check your presentation layer first before doing anything else
if let presoLayer = self.presentationLayer() as? CALayer {
let animation = CABasicAnimation(keyPath: key)
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear);
animation.fromValue = presoLayer.valueForKey(key);
animation.duration = 0.2
return animation;
}
}
return super.actionForKey(key)
}
I'm assuming the rest of your code is right here and just answering the part about the optionality of presentationLayer
. I switched your switch
to an if
because it seemed more readable to me.
Upvotes: 1