swift

CAAnimation completion callback block

onedayitwillmake No Comments

It’s really useful to fire a function when an animation is complete.
There’s no built in way to do that in CoreAnimation, it does have the concept of delegate’s, which get you half way there.

However if you have multiple animations firing, and your delegate is catching everything, you’re gonna be in for a world of hurt.

Here is a simple Swift class I wrote to extend CAAnimation to accept onStart/onCompletion blocks:


import Foundation import Cocoa public typealias CAAnimationCallback = (CAAnimation, Bool) -> (); public class CAAnimationDelegate:NSObject { var onStartCallback:CAAnimationCallback? var onCompleteCallback:CAAnimationCallback? override public func animationDidStart(anim: CAAnimation) { if let startHandler = onStartCallback { startHandler(anim, true); } } override public func animationDidStop(anim: CAAnimation, finished flag: Bool) { if let completionHandler = onCompleteCallback { completionHandler(anim, flag); } } } public extension CAAnimation { // See if there is already a CAAnimationDelegate handling this animation // If there is, add onStart to it, if not create one func setonStartCallbackBlock(callback:CAAnimationCallback) { if let myDelegate = delegate { if(myDelegate.isKindOfClass(CAAnimationDelegate)) { let myThing = myDelegate as! CAAnimationDelegate; myThing.onStartCallback = callback; } } else { let callbackDelegate = CAAnimationDelegate(); callbackDelegate.onStartCallback = callback; self.delegate = callbackDelegate; } } // See if there is already a CAAnimationDelegate handling this animation // If there is, add onCompletion to it, if not create one func setCompletionBlock(callback:CAAnimationCallback) { if let myDelegate = delegate { if(myDelegate.isKindOfClass(CAAnimationDelegate)) { let myThing = myDelegate as! CAAnimationDelegate; myThing.onCompleteCallback = callback; } } else { let callbackDelegate = CAAnimationDelegate(); callbackDelegate.onCompleteCallback = callback; self.delegate = callbackDelegate; } } }

Usage

var animation = CABasicAnimation(keyPath: "strokeEnd")
animation.duration = duration
animation.fromValue = 0.0
animation.toValue = 1.0
animation.setCompletionBlock({ (anim:CAAnimation) in
  Swift.print("On Complete!")
})

CAAnimation delegate not working (Swift)

onedayitwillmake No Comments

CAAnimation provides a way of receiving a callback upon start or completion of an animation.
If you have a ‘pure’ class, that is a class that does not inherit from anything, doing this will have no effect:


class Petal { func startAnimation(duration: Double = 2.0) { let pathAnimation = CABasicAnimation(keyPath: "strokeEnd"); pathAnimation!.delegate = self; pathAnimation!.duration = duration; pathAnimation!.fromValue = 0.0; pathAnimation!.toValue = 1.0; self.shapeLayer.addAnimation(pathAnimation!, forKey: "strokeEnd"); } func animationDidStart(anim: CAAnimation) { Swift.print("ANIMATION DID START!"); } func animationDidStop(anim: CAAnimation, finished flag: Bool) { Swift.print("ANIMATION DID END!"); } }

The reason is because:
You must subclass NSObject, as the delegate methods exist as an informal protocol extension on NSObject

So simply changing it to this is enough:


class Petal:NSObject { // Subclass NSObject func startAnimation(duration: Double = 2.0) { .... } // These are now overrides override func animationDidStart(anim: CAAnimation) { Swift.print("ANIMATION DID START!"); } override func animationDidStop(anim: CAAnimation, finished flag: Bool) { Swift.print("ANIMATION DID END!"); } }

Numeric operator overloading in Swift

onedayitwillmake No Comments

Sometimes when developing in Swift if you’re trying to do seemingly simple things like divide 2 numbers:

let interval:Double = 1.0/fps;

You’ll get errors like these:

binary operator '*' cannot be applied to operands of type 'CGFloat' and 'Double'
binary operator '*' cannot be applied to operands of type 'Int' and 'CGFloat'
cannot convert value of type 'Float' to expected argument type 'Double'
binary operator '*' cannot be applied to operands of type 'CGFloat' and 'Int8'

This is because Swift is more strict about how it treats numeric types, and you have to manually cast them to the same type in order for those operations to work.

However cause we can write our own operator in Swift, we can make it so that when it encounters 2 types, it will check to see if we have a matching operator and use that instead.

So as I’ve encountered them, I’ve been appending to a my little NumericOperatorOverloadingExtensions.swift file:

import Foundation

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////// ADDITION ////////////////////////////////////////////////////////////////
public func +(a: Float, scalar: Int)  -> Float  { return a + Float(scalar); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////// MULTIPLICATION  //////////////////////////////////////////////////////////////
// Int *
public func *(a: Int, scalar: CGFloat)  -> CGFloat  { return CGFloat(a) * scalar; }
public func *(a: Int, scalar: Float)    -> Float    { return Float(a) * scalar; }
public func *(a: Int, scalar: Double)   -> Double   { return Double(a) * scalar; }
public func *(scalar: CGFloat, a: Int)  -> CGFloat  { return CGFloat(a) * scalar; }
public func *(scalar: Float, a: Int)    -> Float    { return Float(a) * scalar; }
public func *(scalar: Double, a: Int)   -> Double   { return Double(a) * scalar; }

// Int8 *
public func *(a: Int8, scalar: CGFloat)  -> CGFloat  { return CGFloat(a) * scalar; }
public func *(a: Int8, scalar: Float)    -> Float    { return Float(a) * scalar; }
public func *(a: Int8, scalar: Double)   -> Double   { return Double(a) * scalar; }
public func *(scalar: CGFloat, a: Int8)  -> CGFloat  { return CGFloat(a) * scalar; }
public func *(scalar: Float, a: Int8)    -> Float    { return Float(a) * scalar; }
public func *(scalar: Double, a: Int8)   -> Double   { return Double(a) * scalar; }

// Int32 *
public func *(a: Int32, scalar: CGFloat)  -> CGFloat  { return CGFloat(a) * scalar; }
public func *(a: Int32, scalar: Float)    -> Float    { return Float(a) * scalar; }
public func *(a: Int32, scalar: Double)   -> Double   { return Double(a) * scalar; }
public func *(scalar: CGFloat, a: Int32)  -> CGFloat  { return CGFloat(a) * scalar; }
public func *(scalar: Float, a: Int32)    -> Float    { return Float(a) * scalar; }
public func *(scalar: Double, a: Int32)   -> Double   { return Double(a) * scalar; }

// Float *
public func *(a: Float, scalar: Double)  -> Float  { return a * Float(scalar); }
public func *(a: Float, scalar: Double)  -> CGFloat  { return CGFloat(a * Float(scalar)); }
public func *(a: Float, scalar: Double)  -> Double  { return Double(a) * scalar; }

// CGFLOAT  *
public func *(a: CGFloat, scalar: Double)  -> CGFloat  { return a * CGFloat(scalar); }
public func *(a: CGFloat, scalar: Double)  -> Float  { return Float(a) * Float(scalar); }
public func *(a: CGFloat, scalar: Double)  -> Double  { return Double(a) * scalar; }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////// DIVISION ////////////////////////////////////////////////////////////////
// Double /
public func /(a: Double, b: Int)  -> Double  { return a / Double(b); }
public func /(a: Double, b: Float)  -> Double  { return a / Double(b); }
public func /(a: Double, b: Int)  -> Int  { return Int(a) / b; }
public func /(a: Int, b: Double)  -> Double  { return Double(a) / b; }
public func /(a: Int, b: Double)  -> Int  { return Int(Double(a) / b); }

// Float /
public func /(a: Float, b: Int)  -> Float  { return a / Float(b); }
public func /(a: Float, b: Int)  -> Int  { return Int(a) / b; }
public func /(a: Int, b: Float)  -> Float  { return Float(a) / b; }
public func /(a: Int, b: Float)  -> Int  { return Int(Float(a) / b); }
public func /(a: Float, scalar: Double)  -> Float  { return a / Float(scalar); }