Adding a view to the window hierarchy
The error is telling you exactly what's going on.
Warning: Attempt to present <AppName.PauseScreen: 0x7fae61fe5ff0> on <AppName.StartScreenViewController: 0x7fae61f79980> whose view is not in the window hierarchy!
(UIApplication.sharedApplication().delegate as AppDelegate).window?.rootViewController
is pointing to an instance of StartScreenViewController
. This is bad: rootViewController
should point to an instance of GameScene
.
The root cause must be how GameScene
is presented. From your description:
The "StartScreenViewController" is the view controller… It then goes to the "GameScene"…
This must be where your problem is. How do you go to GameScene
from StartScreenViewController
?
My guess is that you are adding a new window to the application. You need to set the rootViewController
instead.
let gameScene = UIStoryboard(name: "Main", bundle:nil).instantiateViewControllerWithIdentifier("GameSceneID") as UIViewController
let appDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
appDelegate.window?.rootViewController = gameScene
When you go back to the start screen, you again set the rootViewController
.
let initialViewController = UIStoryboard(name: "Main", bundle:nil).instantiateInitialViewController() as UIViewController
let appDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
appDelegate.window?.rootViewController = initialViewController
You can use transitionFromViewController(,toViewController:, duration:, options:, animations:, completion:)
to animate setting the root view controller.
How do I add a view to the top of an app in iOS 13/14
You have to create a second UIWindow
, assign the rootViewController
and make it visible.
The code bellow is for SwiftUI, but you can do the same with UIKit, just create a window and set window.isHidden = false
.
let secondWindow = UIWindow(windowScene: windowScene)
secondWindow.frame = CGRect(x: 0, y: 40, width: UIScreen.main.bounds.size.width, height: 100)
let someView = Text("I am on top of everything")
secondWindow.rootViewController = UIHostingController(rootView: someView)
secondWindow.isHidden = false
Depending on how many windows you have. You might need to change the windowLevel
of your second window.
You can check if the window is displayed using Debug View Hierarchy
from Xcode.
This is a UIKit example without SceneDelegate. If you have scene delegate you have to pass the window scene to the UIWindow init.
Don't forget to retain the second window.
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
private enum Constants {
static let sessionConfiguration = URLSessionConfiguration.default
}
var window: UIWindow?
var secondWindow: UIWindow?
// MARK: - UIApplicationDelegate
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
let window = UIWindow(frame: UIScreen.main.bounds)
self.window = window
let viewController = UIViewController()
viewController.view.backgroundColor = .red
window.rootViewController = viewController
window.makeKeyAndVisible()
let secondWindow = UIWindow()
secondWindow.frame = CGRect(
x: 0,
y: 40,
width: UIScreen.main.bounds.size.width,
height: 100
)
let secondController = UIViewController()
secondController.view.backgroundColor = .blue
secondWindow.rootViewController = secondController
secondWindow.isHidden = false
self.secondWindow = secondWindow
return true
}
}
presenting whose view is not in the window hierarchy warning
Your LoginVC
is perfectly fine.
However, you need to change your HomeVC
as @Sh_Khan suggested and move the testing code from viewDidLoad
to viewDidAppear
:
import UIKit
import Firebase
class HomeVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
// HomeVC.view was added to a view hierarchy
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// to check whether the user has already logged in or not
Auth.auth().addStateDidChangeListener { (auth, user) in
if user == nil {
let login = self.storyboard?.instantiateViewController(withIdentifier: "login") as! LoginVC
self.present(login, animated: true, completion: nil)
}
}
}
}
Explanation
Your viewDidLoad
method gets called before the viewController
gets presented, so it at that moment it cannot really present another view controller (since it itself is not presented), viewDidLoad
documentation:
Called after the controller's view is loaded into memory.
This method is called after the view controller has loaded its view hierarchy into memory. This method is called regardless of whether the view hierarchy was loaded from a nib file or created programmatically in the loadView() method. You usually override this method to perform additional initialization on views that were loaded from nib files.
In that moment the viewController is not in the window hierarchy yet.
viewDidAppear
however gets called when the view
is presented and becomes a part of the window hierarchy, viewDidAppear
documentation:
Notifies the view controller that its view was added to a view hierarchy.
You can override this method to perform additional tasks associated with presenting the view. If you override this method, you must call super at some point in your implementation.
Don't forget to call super.viewDidAppear
during overriding it.
Root View Controller's view not in the Window Hierarchy
you can get the root view controller of the window, which should be the navigation controller, and then get its top view controller.
try like this:if you are sure there is a viewController.presentedViewController then send includeModal as YES.
- (UIViewController *)topmostViewControllerFrom:(UIViewController *)viewController
includeModal:(BOOL)includeModal
{
if ([viewController respondsToSelector:@selector(selectedViewController)])
return [self topmostViewControllerFrom:[(id)viewController selectedViewController]
includeModal:includeModal];
if (includeModal && viewController.presentedViewController)
return [self topmostViewControllerFrom:viewController.presentedViewController
includeModal:includeModal];
if ([viewController respondsToSelector:@selector(topViewController)])
return [self topmostViewControllerFrom:[(id)viewController topViewController]
includeModal:includeModal];
return viewController;
}
Swift 4 Attempt to present ViewController whose view is not in the window hierarchy
This issue happens due to your view hierarchy.
You need to find out what is your Current/Topmost view controller in
view hierarchy and present your alert over it.
To find out topmost view controller use following code:
func getTopMostViewController() -> UIViewController? {
var topMostViewController = UIApplication.shared.keyWindow?.rootViewController
while let presentedViewController = topMostViewController?.presentedViewController {
topMostViewController = presentedViewController
}
return topMostViewController
}
And present your alert over topmost view controller and use main thread to present an alert because closures may have working on another thread.
DispatchQueue.main.async {
getTopMostViewController()?.present(alertController, animated: true, completion: nil)
}
Please refer to this stack answer:
Swift 3 Attempt to present whose view is not in the window hierarchy
SwiftUI - Timing of views getting added to the window hierarchy when using a List
It is a bit early, activate full screen on view appeared, like below (tested with Xcode 12 / iOS 14)
struct ComplicatedView: View {
@State private var showingCover = false
var body: some View {
DetailsOfComplicatedView()
.fullScreenCover(isPresented: $showingCover, content: {
TutorialView()
})
.onAppear { self.showingCover = true }
}
}
Swift 3 Attempt to present whose view is not in the window hierarchy
I have resolved the issue the main problem is exactly what it says the view is not in the view hierarchy. In order to resolve this issue we need to set the root view controller to the current view controller using the appDelegate object. So that the view now comes in the view hierarchy and be able to present further views. Here is the code
let initialViewController = UIStoryboard(name: "Main", bundle:nil).instantiateInitialViewController() as UIViewController
let appDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
appDelegate.window?.rootViewController = initialViewController
Please read this for further information. https://stackoverflow.com/a/27608804/5123516
Is MyViewController in the window hierarchy?
The view controller's view
will have its window
property set if its in the hierarchy
if MyViewController.view.window != nil {
// In the window hierarchy
}
iOS whose view is not in the window hierarchy
That happen because of two viewcontroller present and dismiss at a same time or you are trying to present ViewController immediately at the viewcontroller open ViewDidload
method so
First:
- Present ViewController from
viewDidAppear
Method or instead ofViewDidload
.
Second:
I suggest to make use of completion method for present and dismiss viewcontrolelr like following example:
[self presentViewController:lOTPViewController animated:YES
completion:^{
}];
UPDATE:
Create a separate method of presenting a OTPViewController like following:
-(void)PresentOTPViewController
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
OTPViewController *lOTPViewController = [storyboard instantiateViewControllerWithIdentifier:@"OTPViewController"];
lOTPViewController.comingFromReg = true;
[self presentViewController:lOTPViewController animated:YES
completion:^{}];
}
Now call this method with 1 second Delaya using performSelector
[self performSelector:@selector(PresentOTPViewController) withObject:self afterDelay:1.0 ];
You need to put above performselect code in
[self dismissViewControllerAnimated:YES completion:^{
[self performSelector:@selector(PresentOTPViewController) withObject:self afterDelay:1.0 ];
}]; // this is the dismiss method of PassCodeViewController
t
Related Topics
How to Get Date and Time to Show a Clock in Uilabel
Open a Viewcontroller from Remote Notification
Reading an Inputstream into a Data Object
Uitableview - Multiple Selection and Single Selection
Simple Clickable Link in Cocoa and Swift
Input Type=File Not Working in Webview of Os X Application
Calculate Area of Mkpolygon in an Mkmapview
Translucent Status Bar with No Navigation Bar
Find Item of Specific Type in Array
App Crash on Sign in (Xcode 9.3) Exc_Bad_Access (Code=1, Address=0X1)
Wait Until an Asynchronous API Call Is Completed - Swift/Ios
Need to Check That Braces in Given Array Are Balanced or Not
How to Change Colour of the Certain Words in Label - Swift 3
How Is a Return Value of Anyobject! Different from Anyobject
Spritekit - Create at Random Position Without Overlapping