Calling completion handler of a function from Timer selector function Swift

Viewed 973

I have animateButtons() function of which I need to set completion handler only when the animation has finished. The problem is that in animateButtons() I can only set the completion handler just after imageView.startAnimating() so the whole timing gets compromised, as it's completion is used to launch other animations. I read in a another post with same exact issue, that I should set an NSTimer to set the completion handler , as I actually thought of doing, but I don't really know how to . I have set NSTimer to call setCompletion() function, but how would I set it to call animateButtons() completion handler ?

Can you point me in the right direction?

This is the function and the selector function:

static func animateButtons(completed: @escaping(Bool) ->(), imageView: UIImageView, images: [UIImage]) {
        imageView.animationImages = images
        imageView.animationDuration = 1.0 // check duration
        imageView.animationRepeatCount = 1
        imageView.startAnimating()

        _ = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(setCompletion), userInfo: nil, repeats: false)
        // completed(true)
}

@objc func setCompletion() {

}
2 Answers

You can try to use inline callback

static func animateButtons(completed: @escaping(Bool) ->(), imageView: UIImageView, images: [UIImage]) {
    imageView.animationImages = images
    imageView.animationDuration = 1.0 // check duration
    imageView.animationRepeatCount = 1
    imageView.startAnimating() 
    Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false, block: { (t) in 
        t.invalidate()
        completed(true)
    })
}

BTW a dispatch after can do the job also

static func animateButtons(completed: @escaping(Bool) ->(), imageView: UIImageView, images: [UIImage]) {
    imageView.animationImages = images
    imageView.animationDuration = 1.0 // check duration
    imageView.animationRepeatCount = 1
    imageView.startAnimating()
    DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
        completed(true)
    }
}

Approach 1 (I prefer this one) (If you are animating Gif images) Use a third-party library like Gifu https://github.com/kaishin/Gifu to calculate the runtime of your gif. It will work even if you change the gif image in the future.

    static func animateButtons(completed: @escaping(Bool) ->(), imageView: UIImageView, images: [UIImage]) {
imageView.prepareForAnimation(withGIFNamed: "welcome", loopCount: 1) {
            self.imageView.startAnimatingGIF()
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.2 + self.imageView.gifLoopDuration, execute: {
                // Do your Task after animation completes
                )
        }
}

Approach 2 (Calculate the run Time of the animation and set a timer)

Related