Blocks on Swift (animateWithDuration:animations:completion:)

IosSwiftClosures

Ios Problem Overview


I'm having trouble making the blocks work on Swift. Here's an example that worked (without completion block):

UIView.animateWithDuration(0.07) {
    self.someButton.alpha = 1
}

or alternatively without the trailing closure:

UIView.animateWithDuration(0.2, animations: {
    self.someButton.alpha = 1
})

but once I try to add the completion block it just won't work:

UIView.animateWithDuration(0.2, animations: {
    self.blurBg.alpha = 1
}, completion: {
    self.blurBg.hidden = true
})

The autocomplete gives me completion: ((Bool) -> Void)? but not sure how to make it work. Also tried with trailing closure but got the same error:

! Could not find an overload for 'animateWithDuration that accepts the supplied arguments

Update for Swift 3 / 4:

// This is how I do regular animation blocks
UIView.animate(withDuration: 0.2) {
    <#code#>
}

// Or with a completion block
UIView.animate(withDuration: 0.2, animations: {
    <#code#>
}, completion: { _ in
    <#code#>
})

I don't use the trailing closure for the completion block because I think it lacks clarity, but if you like it then you can see Trevor's answer below.

Ios Solutions


Solution 1 - Ios

The completion parameter in animateWithDuration takes a block which takes one boolean parameter. In Swift, like in Obj-C blocks, you must specify the parameters that a closure takes:

UIView.animateWithDuration(0.2, animations: {
    self.blurBg.alpha = 1
}, completion: {
    (value: Bool) in
    self.blurBg.hidden = true
})

The important part here is the (value: Bool) in. That tells the compiler that this closure takes a Bool labeled 'value' and returns Void.

For reference, if you wanted to write a closure that returned a Bool, the syntax would be

{(value: Bool) -> bool in
    //your stuff
}

Solution 2 - Ios

The completion is correct, the closure must accept a Bool parameter: (Bool) -> (). Try

UIView.animate(withDuration: 0.2, animations: {
    self.blurBg.alpha = 1
}, completion: { finished in
    self.blurBg.hidden = true
})

Solution 3 - Ios

Underscore by itself alongside the in keyword will ignore the input

Swift 2

UIView.animateWithDuration(0.2, animations: {
    self.blurBg.alpha = 1
}, completion: { _ in
    self.blurBg.hidden = true
})

Swift 3, 4, 5

UIView.animate(withDuration: 0.2, animations: {
    self.blurBg.alpha = 1
}, completion: { _ in
    self.blurBg.isHidden = true
})

Solution 4 - Ios

There is my solution above based on accepted answer above. It fades out a view and hiddes it once almost invisible.

Swift 2

func animateOut(view:UIView) {
    
    UIView.animateWithDuration (0.25, delay: 0.0, options: UIViewAnimationOptions.CurveLinear ,animations: {
        view.layer.opacity = 0.1
        }, completion: { _ in
            view.hidden = true
    })   
}

Swift 3, 4, 5

func animateOut(view: UIView) {
    
    UIView.animate(withDuration: 0.25, delay: 0.0, options: UIView.AnimationOptions.curveLinear ,animations: {
        view.layer.opacity = 0.1
    }, completion: { _ in
        view.isHidden = true
    })
}

Solution 5 - Ios

Here you go, this will compile

Swift 2

UIView.animateWithDuration(0.3, animations: {
    self.blurBg.alpha = 1
}, completion: {(_) -> Void in
    self.blurBg.hidden = true
})

Swift 3, 4, 5

UIView.animate(withDuration: 0.3, animations: {
    self.blurBg.alpha = 1
}, completion: {(_) -> Void in
    self.blurBg.isHidden = true
})

The reason I made the Bool area an underscore is because you not using that value, if you need it you can replace the (_) with (value : Bool)

Solution 6 - Ios

Sometimes you want to throw this in a variable to animate in different ways depending on the situation. For that you need

 let completionBlock : (Bool) -> () = { _ in 
 }

Or you could use the equally verbose:

 let completionBlock = { (_:Bool) in 
 }

But in any case, you have have to indicate the Bool somewhere.

Solution 7 - Ios

SWIFT 3.x + 4.x

I'd like to make an update and simplify the things.

Example below is implemented in any view it is hiding slowly and when it is completely transparent; removes it self from parent view

ok variable will always returns true with animation termination.

    alpha = 1
    UIView.animate(withDuration: 0.5, animations: {
        self.alpha = 0
    }) { (ok) in
        print("Ended \(ok)")
        self.removeFromSuperview()
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmanolosaviView Question on Stackoverflow
Solution 1 - IosZaksoupView Answer on Stackoverflow
Solution 2 - IosNicholas H.View Answer on Stackoverflow
Solution 3 - IosDan GreenfieldView Answer on Stackoverflow
Solution 4 - IosJaroView Answer on Stackoverflow
Solution 5 - IosKris GellciView Answer on Stackoverflow
Solution 6 - IosDan RosenstarkView Answer on Stackoverflow
Solution 7 - IosTrevorView Answer on Stackoverflow