Issue with UIViewController maintaining forced rotation orientation

Hi, I am having trouble with a phenomenon where after forcing a UIViewController to rotate, the orientation is maintained again in the same process.

The project is very simple, UINavigationController -> ViewControllerA to ViewControllerB in full screen. In Deployment Info -> iPhone Orientation, check Portrait and Requiers full screen.

UIViewControllerA.swift

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask{
        return .portrait
    }

    @IBAction func createFullScreenAction(_ sender: Any) {
        if let controller = self.storyboard?.instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            controller.modalPresentationStyle = .fullScreen
            self.present(controller, animated: true)
        }
    }

ViewControllerB has a process to force rotation.

UIViewControllerB.swift

    override func viewDidLoad() {
        super.viewDidLoad()
        let delegate = UIApplication.shared.delegate as! AppDelegate
        delegate.isFullScreen = true
    }
    
    @IBAction func rotateAction(_ sender: Any) {
        if #available(iOS 16.0, *) {
            let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
            guard let windowScene = windowScene else {
                return
            }
            windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: windowScene.interfaceOrientation.isPortrait ? .landscape : .portrait)){
                    error in
                    print(error)
            }
            self.setNeedsUpdateOfSupportedInterfaceOrientations()
        } else {
            let mask: UIDeviceOrientation  = UIApplication.shared.statusBarOrientation == .portrait ? .landscapeLeft : .portrait
            UIDevice.current.setValue(mask.rawValue, forKey: "orientation")
        }
    }

    @IBAction func closeAction(_ sender: Any) {
        let delegate = UIApplication.shared.delegate as! AppDelegate
        delegate.isFullScreen = false
        self.dismiss(animated: true)
    }

AppDelegate.swift sets the direction of rotation when ViewControllerB is displayed.

AppDelegate.swift

    var isFullScreen:Bool  = false

    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        
        if isFullScreen {
            return .all
        }
        return .portrait;
    }

This project is very simple: ViewControllerA does not allow rotation, but only portrait orientation; ViewControllerB allows rotation in all directions, and the rotateAction() method in ViewControllerB forces the rotation process. When the screen is closed with the closeAction() method and returned to ViewControllerA, the screen returns to portrait orientation.

The following operation pattern results in a behavior that is unintended for me. Most people will probably feel the same way. This is the same behavior in the simulator and on the actual device. I have also confirmed that it is the same behavior on iOS 12-16.

  1. Launch the application.
  2. Open ViewControllerB from ViewControllerA while holding it vertically.
  3. Force rotation with ViewControllerB while holding it vertically (execute rotateAction). The content will be horizontal.
  4. Close ViewControllerB while holding it vertically (execute closeAction); it returns to ViewControllerA and the contents become vertical.
  5. Open ViewControllerB again from ViewControllerA while holding it vertically. The contents will be in the same horizontal direction as the process in 3)

Since the iPhone is normally held vertically, the process in 5) expects the image to be displayed in portrait orientation, but it is displayed in the orientation rotated in 3). A sample is available on GitHub to help you see how it works. https://github.com/team-chaconne/RotationSample

You can experience this phenomenon with the simulator, and there is also a video that reproduces the phenomenon on the issue.

https://github.com/team-chaconne/RotationSample/issues/1

If I allow all directions of rotation of ViewControllerA, not just portrait, I can solve this problem since it rotates the device, but for several reasons, I would like to limit ViewControllerA to portrait only.

I tried to get the exact orientation of the device at the time ViewControllerB is displayed. I decided that UIDevice.current.orientation was not usable right now because it returned information other than portrait and landscape. Also, view.windowScene.interfaceOrientation sometimes returned a value that was landscape even though it was still held portrait.

Is this a UIKit specification? Is there a project setting, method to check, or workaround?

Issue with UIViewController maintaining forced rotation orientation
 
 
Q