Modally present VC from UITabBarController in AppDelegate - ios

I'm trying to trigger a modal view from the AppDelegate every time the app is opened. I can see my breakpoint being hit, but the modal never shows. I'm including an image of my storyboard in case it matters. It's a fairly simple app right now with a 2 tab tab bar controller.
This is the code I have in the AppDelegate to trigger it.
let newVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LoginView")
let view = window?.rootViewController as! UITabBarController
view.selectedViewController?.show(newVC, sender: nil)

It seems newVC is not in the tab bar's controllers array, and you're attempting to modally present it from the selectedViewController in AppDelegate where there probably isn't a selected view controller yet.
One solution is to present newVC after viewDidLoad of the selected view controller (view controller at selectedIndex). If the presentation must take place before any of the tab bar's view controllers are loaded, then you might wanna set it as the window's root view controller and set the root to be the tab bar once newVC has finished its business.

Related

assigning a custom destination to popToRootViewController swift 4

I am using navigationController?.popToRootViewController(animated: true) to dismiss my current view to the previous view. My view controller relationship looks like this.
VC1->VC2
VC1->VC3
VC3->VC2
Whenever the client is in VC2 I want to pop the navigation controller back to VC1. This works fine when the rootviewcontroller is set to VC1. However, when the client uses a segue from VC3 to enter VC2, the rootviewcontroller is set to VC3 and the navigation controller pops to VC3.
I tried to change the rootviewcontroller like this.
// set root view controller
let appdelegate = UIApplication.shared.delegate as! AppDelegate
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let VC1 = mainStoryboard.instantiateViewController(withIdentifier: "VC1") as! FirstViewController
appdelegate.window!.rootViewController = VC1
navigationController?.popToRootViewController(animated: true)
But this actually returns the viewcontroller to the root view controller (VC1) even before the line "navigationController?.popToRootViewController(animated: true)" is executed so there is no animation.
Is there any way to set the rootviewcontroller of a navigation controller without presenting the root view controller right away?
If you put appdelegate.window!.rootViewController = VC1, the stack of controllers has died, you only have in the stack an alone Controller, therefore you can't apply popToRootViewController.
If this is your required navigation, maybe, this post helps you:

Modal view doesn't cover whole screen

I have an app that I need to display a pin code screen every time the app is opened. I'm successfully displaying the modal view, but it doesn't cover the navigation bar at the top, and it doesn't cover the tab bar at the bottom. I believe it's because of how I'm presenting it, but I'm not seeing a way to change it.
This is how I'm presenting the controller
let newVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LoginView")
let view = window?.rootViewController as! UITabBarController
view.selectedViewController?.show(newVC, sender: nil)
This is the storyboard to give you an idea of the app.
The problem is your use of UIViewController's api, show. The function is overridden by UINavigationController in this case and push will be used to present the view controller. If your plan is to modally present a view controller, rather use present
selectedViewController?.present(newVC, animated: true, completion: nil)

Log out and clear VCs below current VC

We are looking to change the way a user logs out of our app. In order to do that, we want to dismiss all the VCs below the current VC and put another VC on top as the root VC. Right now we are doing this which I believe does not dismiss any VC below from memory.
let viewController = storyboard?.instantiateViewController(withIdentifier: "SignIn")
if let unwrappedViewController = viewController {
self.present(unwrappedViewController, animated: true, completion: {})
}
The problem is that the VC that we want to put on top is not embedded in a Navigation Controller or tab bar controller. How would we dismiss the VCs and set the new VC as the main VC as if the user was opening the app for the first time without having previously logged in? We also do want the transition to be animated with whatever animation is normal for that event (modal animation is fine). I have read a bunch of different ways on doing it but I want to know which way is best practice and should be implemented specifically dismissing all VCs and putting a new VC that isn't in a Nav controller on top.
If you can access the UIWindow of the app, you can set its rootViewController property to your sign-in view controller, effectively removing all current view controllers and adding the sign-in view controller instead. Here's an example:
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
// Should remove all subsequent view controllers from memory.
appDelegate.window?.rootViewController.dismiss(animated: true, completion: nil)
// Set the root view controller to a new instance of the sign in view controller.
appDelegate.window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SignIn")

Push Notification TabBar Does not appear

In didReceiveRemoteNotification I have
let storyboard = UIStoryboard(name: "RAV", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "AdvanceViewController") as! AdvanceViewController
window?.rootViewController = vc
Inside the app when I navigate to AdvanceViewController the tabBar works, but when I'm open by push, it does not appear.
The Push Works, what does not work it's tabBar
Does anyone know how to do fix it?
The tab bar does not display because you instantiated the view which lies in the tab bar as the root view controller, but that would mean that it is the root controller now, not the tabbar (but you want the tabbar to be the root view controller). What you need to do is set the root view controller to the tab bar and then set the tab bar to the correct index.

How can I conditionally animate a storyboard segue in iOS?

I've added a Quick Action to my iOS app. When I handle the action, I perform a modal segue I created in the storyboard. If the app is already launched, it comes to the foreground with the destination view controller already visible. However, if the app is not already launched, you see the presenting view controller and then the destination view controller animates into view. I'd like to make it so when you select the Quick Action, you see the destination view controller without it animating into view.
You have to set your ViewController as your app's rootViewController in App Delegate. You can do that like this.
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let rootViewController = mainStoryboard.instantiateViewControllerWithIdentifier("YouControllersStoryBoardIDHere")
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window!.rootViewController = rootViewController
self.window!.makeKeyAndVisible()
Put this code in your App Delegat's didFinishLaunchingWithOptions method.
Check your Quick Actions type, corresponding to that call this with appropriate view controller's storyboard id.

Resources