Why is presentationController.delegate creating a retain cycle when in a navigation stack

I was stumbeling upon a retain cycle in UIKit frequently since the introduction of iOS 13 and I cannot explain myself why this is creating a retain cycle


class TestVC: UIViewController, UIAdaptivePresentationControllerDelegate {
    deinit {
        print("No leak")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .red
        presentationController?.delegate = self
    }

    func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
        print("dismiss")
    }
}

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIViewController()
            self.window = window
            window.makeKeyAndVisible()
            let nav = UINavigationController(rootViewController: TestVC())
            window.rootViewController?.present(nav, animated: true)
        }
    }

}

First, the presentationController delegate is never called. Secondly, the VC is never deallocated when swiping it away. When using tthe memory debugger I see the NavigationController still holden a strong reference to the TestVC. How is this creating a retain cycle when the presentationController.delegate is a weak var?
So far the only work around I have found was checking if there is a parent view controller in viewWillAppear and not set the presentationController.delegate in that case.

Accepted Reply

To answer my own question:
The leak is caused through acccessing the presentationController property of TestVC. Since, the VC is not presented but pushed, accessing this property creates a new PresentationController which then strongly retains the VC.

Replies

To answer my own question:
The leak is caused through acccessing the presentationController property of TestVC. Since, the VC is not presented but pushed, accessing this property creates a new PresentationController which then strongly retains the VC.

But who retains the new PresentationController? I just ran into this, and it sure feels like a leak to me.