Why is animation parameter for UIView.transition(with:duration:options:animations:completion:) optional

https://developer.apple.com/documentation/uikit/uiview/1622574-transition specifies for the animation parameter:

This parameter must not be NULL.

Yet the animation parameter is defined as (() -> Void)? and passing nil seems to work fine, performing an animation on the latest update to the with view.

Possibly because "NULL" is not the same as "nil"!

At least... they are the same, but they aren't.

  • NULL is a generic pointer value
  • nil is the absence of a value of a certain type

See https://swiftbydeya.com/swift-the-difference-between-nil-nil-null-nsnull/

I tested the following:

    var animationContainerView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()
        animationContainerView = UIView(frame: view.bounds)
        animationContainerView.frame = view.bounds
        view.addSubview(animationContainerView)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print("APPEAR")
        let newView = UIImageView(image: UIImage(named: "Sa Riera"))
        newView.center = animationContainerView.center
        UIView.transition(with: animationContainerView,
                          duration: 0.33,
                          options: [.curveEaseOut, .transitionFlipFromBottom],
                          animations:  { self.animationContainerView.addSubview(newView)  },
                          completion: { _ in print("COMPLETED")}
        )
    }

As expected, I get the image appear with the transition animation, and logs

  • APPEAR
  • COMPLETED

I then tested with nil animation:

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print("APPEAR")
        let newView = UIImageView(image: UIImage(named: "An image"))
        newView.center = animationContainerView.center
        UIView.transition(with: animationContainerView,
                          duration: 0.33,
                          options: [.curveEaseOut, .transitionFlipFromBottom],
                          animations: nil,
                          completion: { _ in print("COMPLETED")}
        )
    }

No crash; I get the expected logs

  • APPEAR
  • COMPLETED

So, animations: nil works, doing nothing.

I tested with empty closure

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print("APPEAR")
        let newView = UIImageView(image: UIImage(named: "An image"))
        newView.center = animationContainerView.center
        UIView.transition(with: animationContainerView,
                          duration: 0.33,
                          options: [.curveEaseOut, .transitionFlipFromBottom],
                          animations: { },
                          completion: { _ in print("COMPLETED")}
        )
    }

Same result, nothing but no crash and correct log.

I tested passing a func:

    var newView = UIImageView()

    func transition() {
        self.animationContainerView.addSubview(newView)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print("APPEAR")
        newView = UIImageView(image: UIImage(named: "An image"))
        newView.center = animationContainerView.center
        UIView.transition(with: animationContainerView,
                          duration: 0.33,
                          options: [.curveEaseOut, .transitionFlipFromBottom],
                          animations: transition,
                          completion: { _ in print("COMPLETED")}
        )
    }

Works as well, image appears with animation effect.

and finally passing a nil func:

    var transition: (() -> Void)? = nil

No crash there either.

So it seems doc only means that passing nil will result in doing nothing ?

Not clear then why this warning in doc nor why animation parameter is an optional.

Why is animation parameter for UIView.transition(with:duration:options:animations:completion:) optional
 
 
Q