UIViewPropertyAnimator has an addCompletion
method that lets you provide a block of code to be executed when the animation ends:
func addCompletion(_ completion: @escaping (UIViewAnimatingPosition) -> Void)
When I try to use an animator in a Task and I call that method, I get a warning:
| Consider using asynchronous alternative function
Sure enough, there is an asynchronous alternative function:
func addCompletion() async -> UIViewAnimatingPosition
But I can’t make any sense of this. Where’s the block that is to be run when the animation completes? In fact, I find that if I call this method, any code that follows isn’t even run. Is this just some massive bug in Apple’s provision of async/await alternatives?
Here’s an artificial example for use in a view controller:
override func viewDidLoad() {
super.viewDidLoad()
Task {
UIViewPropertyAnimator.runningPropertyAnimator(
withDuration: 2,
delay: 2,
options: [],
animations: {
self.view.alpha = 0
}
).addCompletion { [weak self] _ in
self?.view.alpha = 1
}
}
}
You will see the warning on the .addCompletion
line. How would you rewrite the code so that it still works (the view disappears and then reappears) but the warning goes away?
2
Answers
Just
await
the completion and set the alpha value back to 1This is part of the Objective-C interoperability for methods with completion handlers:
So, what you see is expected behaviour. Agreed, it looks really strange, you might’ve run in one of those not-so-nice corner cases, but it’s just how the compiler translates by default the async-compatible Objective-C functions.
Anyhow, a workaround to get rid of the warning, and still keep the
Task
, is to wrap the animation within aMainAction.run
call. The closure passed to toMainAction.run
is non-async, so the warning will go away.