Issue with presenting viewcontroller in iOS 13, Xcode 11

Viewed 6281

I'm trying to present a viewcontroller on topMostViewController. It's working in iOS 12 and lower. But on iOS 13 I'm getting this error:

Manually adding the rootViewController's view to the view hierarchy is no longer supported. Please allow UIWindow to add the rootViewController's view to the view hierarchy itself.

I have checked on iOS 12 and lower, and the code below works fine. But on iOS 13 I am having trouble presenting the view controller. I printed on viewDidLoad; it's getting printed but the view doesn't appear.

func presentInWindow(animated flag: Bool = true, completion: (() -> Void)? = nil) {

        DispatchQueue.main.async {
            var alertWindow: UIWindow?
            alertWindow = UIWindow(frame: UIScreen.main.bounds)
            alertWindow?.windowLevel = UIWindow.Level.alert + 1
            alertWindow?.rootViewController = UIApplication.topViewController()
            if let rootViewController = alertWindow?.rootViewController {
                alertWindow?.makeKeyAndVisible()
                rootViewController.present(self, animated: flag, completion: completion)
            }
        }

}
static func topViewController() -> UIViewController? {

        var topViewController: UIViewController?

        if #available(iOS 13.0, *) {

            topViewController = shared.connectedScenes
                .filter({$0.activationState == .foregroundActive})
                .map({$0 as? UIWindowScene})
                .compactMap({$0})
                .first?.windows
                .filter({$0.isKeyWindow}).first?.rootViewController
        } else {
            topViewController = shared.delegate?.window??.rootViewController
        }

        while true {
            if let presented = topViewController?.presentedViewController {
                topViewController = presented
            } else if let nav = topViewController as? UINavigationController {
                topViewController = nav.visibleViewController
            } else {
                break
            }
        }

        return topViewController
}
4 Answers

This code will work to create a view controller on top. You can adjust the size of the view controller on this line: popOverVC.view.frame = lSs I'm not sure if this code is exactly what you are asking for, but if you need a quick solution, it will present view controllers in swift 5, iOS 13, and xcode 11. Note that it is a child view controller, so if you remove the parent, it will leave too. Simply change self to ViewController that you want to present on.

    let popOverVC = UIStoryboard(name: "yourSB", bundle: nil).instantiateViewController(withIdentifier: "vcYouWantID") as! vcYouWant
    self.addChild(popOverVC)
    let lSs = UIScreen.main.bounds
    popOverVC.view.frame = lSs
    popOverVC.view.tag = tag
    self.view.addSubview(popOverVC.view)
    popOverVC.didMove(toParent: self)

I received the same error while updating an app which worked fine previously. It looks like the new requirement for AppDelegate.swift is:

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    return true
  }

  // MARK: UISceneSession Lifecycle
  func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
  }
  func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) { }
}

hth

I encountered the same issue tonight. I tried the methods suggested by people on the Net including Stackoverflow, but none had worked.

Just now, as if magic was working, I tried to form an outlet from the ViewController (visually the "background" layer for all subviews) in the Main.storyboard to the ViewConstroller class in ViewController.swift. It worked in my project for iOS 13 simulator in Xcode 12.2.

Hope this trick will also work for you.

I found this to fix my problem (in old Objective-C code):

// old way broken in iOS 13
//appDelegate.window.rootViewController = vc;

// this works in iOS 13
[appDelegate.window setRootViewController:vc];
Related