1

I have a generic NSObject animation class I created for a new project and I'm attempting to refactor some older projects with the new class. All was well until I found some animations w/ completion blocks, which threw off my plan to remove exorbitant amounts of redundant code from my view controllers. Here's what I've got...

Animator.swift

class Animator: NSObject {
    var control: UIControl? // Can accept everything that's a subclass of UIControl

    override init() {
        super.init()
    }

    // FIXME: figure out how to add a completion block as a parameter on a method call
    func animateControl(control: UIControl) {
        control.transform = CGAffineTransformMakeScale(0.75, 0.75)
        UIView.animateWithDuration(0.5,
                                   delay: 0,
                                   usingSpringWithDamping: 0.3,
                                   initialSpringVelocity: 5.0,
                                   options: UIViewAnimationOptions.AllowUserInteraction,
                                   animations: {
                                    control.transform = CGAffineTransformIdentity
        }) { (value: Bool) -> Void in
            // completion block
            // ** method as a parameter goes here? ** 
        }
    }
}

To use it, rather than typing in all stuff to animate a button, I just call the class from MyViewController.swift

MyViewController.swift

// Property declaration
let animator = Animator()

// Tie it to an IBAction
@IBAction func myButtonAction(sender: UIButton) {
    animator.animateControl(sender, methodIWantToRunAfterAnimateControlFinishes)
}

func methodIWantToRunAfterAnimateControlFinishes() {
    // Do Stuff
}

How would I feed animateControl's initializer a method to run as a completion block? I looked at this (not my website, but it's how I feel), but I'm unable to get it to work.

Update

I had to wrestle with the syntax a little bit, but here's the initializer code that got me over the finish line:

func animateControl(control: UIControl, completion: (() -> Void)?) {
    control.transform = CGAffineTransformMakeScale(0.75, 0.75)
    UIView.animateWithDuration(0.5,
                               delay: 0,
                               usingSpringWithDamping: 0.3,
                               initialSpringVelocity: 5.0,
                               options: UIViewAnimationOptions.AllowUserInteraction,
                               animations: {
                                control.transform = CGAffineTransformIdentity
    }) { _ in
        // completion block
        completion?()
    }
}

This handles completion blocks w/ code and nil completion blocks.

2 Answers 2

3

A very simple completion block when used as a parameter looks like this:

onCompletion: (() -> Void)?

The reason why the () -> Void is nullable ? is to be usable in Objective-C. If this isn't needed then you needn't enclose it in brackets nor mark it as nullable ?.

This will let you pass in a function that expects no parameters and returns nothing. You would add this to your signature like so:

func animateControl(control: UIControl, onCompletion: (() -> Void)?)

If you want to add parameters to that, add them into the signature of the completion block:

func animateControl(control: UIControl, onCompletion: ((value: AnyObject) -> Void)?)

The same goes for the return statement:

func animateControl(control: UIControl, onCompletion: ((value: AnyObject) -> AnyObject)?)

Once it's in your function's signature, you can call it by it's name:

func animateControl(control: UIControl, onCompletion: ((value: AnyObject) -> Void)?) {
    //do stuff here
    onCompletion(obj)
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for getting me squared away on this. Greatly appreciated.
1

You can add a completion handler like this and you should be able to call it the way you have it in your example.

func animateControl(control: UIControl, _ completion: (() -> ())? = nil) {
    control.transform = CGAffineTransformMakeScale(0.75, 0.75)
    UIView.animateWithDuration(0.5,
                               delay: 0,
                               usingSpringWithDamping: 0.3,
                               initialSpringVelocity: 5.0,
                               options: UIViewAnimationOptions.AllowUserInteraction,
                               animations: {
                                control.transform = CGAffineTransformIdentity
    }) { _ in
        completion?()
    }
}

1 Comment

Thank you for your help on this! I greatly appreciate it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.