I know that there are already several questions asked about weak in the context of animations like Is it necessary to use unowned self in closures of UIView.animateWithDuration(…)? While it is obvious in the latter case, that you can omit weak, I have still difficulties, to see the reason, why I should not use the weak pattern in Robs answer about a rotating view. I do not want to disturb the comments there, so I ask the question here.
The code in question is
private func createAnimation() {
     animator = UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 4, delay: 0, options: .curveLinear) { [self] in
         UIView.animateKeyframes(withDuration: 4, delay: 0) {
             UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1.0 / 3.0) {
                 animatedView.transform = .init(rotationAngle: .pi * 2 * 1 / 3)
             }
             ...
         }
     } completion: { [weak self] _ in
         self?.createAnimation()
     }
 }
Rob used the [weak self] in the completion-closure but not in the animations-closure, where he actually put self into the capture list to make his intention obvious. How can I know, that UIViewPropertyAnimator.runningPropertyAnimator will never put the (escaping) animations-closure into the created animator-instance-variable?
I don't think, that UIViewPropertyAnimator.runningPropertyAnimator actually captures the animations-closure, but as long as I have no idea, how UIViewPropertyAnimator.runningPropertyAnimator is implemented, or will be implemented in the future, how can I be sure?
Maybe this pseudo-implementation could help to explain, what I mean:
import Foundation
class UIView {
    var transform = CGFloat.zero
    static func animateKeyFrames(animations: () -> Void) {}
    static func addKeyframe(animations: () -> Void) {}
}
class UIViewPropertyAnimator {
    
    var animations: () -> Void = {}
    var completion: (() -> Void)? = {}
    
    static func runningPropertyAnimator(animations: @escaping () -> Void,
                                        completion: (() -> Void)?) -> UIViewPropertyAnimator {
        let animator = UIViewPropertyAnimator()
        animator.animations = animations
        animator.completion = completion
        
        return animator
    }
}
class ViewController {
    var animator: UIViewPropertyAnimator?
    let animatedView = UIView()
    
    func viewDidLoad() {
        createAnimation()
    }
    
    func createAnimation() {
        animator = UIViewPropertyAnimator.runningPropertyAnimator(animations: { [weak self] in
            UIView.animateKeyFrames(animations: {
                UIView.addKeyframe(animations: {
                    self?.animatedView.transform = .zero
                })
            })
        }, completion: { [weak self] in
            self?.animatedView.transform = .zero
        })
    }
    
    deinit {
        print("deinit")
    }
}
func createAndRelease() {
    let viewController = ViewController()
    viewController.viewDidLoad()
}
createAndRelease()
Removing [weak self] from the animations or completion-closure would obviously cause a retain-cycle in my pseudo-code and deinit would never be called.
 
    