Deinit Two ViewController at the same time in Swift - ios

I have two UIViewController. First one is a welcome screen and second one is a login screen (which is inside a navigation Controller). Users can go back to welcome screen from login screen with a back button so login screen opens with self.present(LoginViewController(),animated: false) and after Login Screen, final UIViewController opens with appDelegate.window?.rootViewController = FinalViewController().
My problem is that neither LoginViewController or WelcomeViewController deinit at this scenario. However, If I;
Open FinalViewController (via changing RootViewController) directly from WelcomeViewController, without showing LoginViewController.
Open LoginViewController without showing WelcomeViewController then open FinalViewController (again changing RootViewController)
Controllers deinited. So I don't think any of viewcontroller has a retain cycle vs..
I want to deinit both login and welcome screens after open final controller.
EDIT: I found that putting it inside NavigationController blocks the deniting.
EDIT2: If I call self.dismiss(animated: false, completion: nil) before changing rootViewController. All controllers seems to be deinited but I'm not sure If It will be a better answer.

Why don't you use this hierarchy:
-UIWindow
-----UIWindow.RootViewController
----------UINavigationController
---------------WelcomeScreen
---------------LoginScreen (Push without animation)
On Login Success:
-UIWindow
-----UIWindow.RootViewController
----------UINavigationController
---------------FinalViewController
Hide navigation bar and use animated property as per need.
EDIT
A part from document:
viewControllerToPresent
The view controller to display over the current view controller’s content.
So reference of the parent controller can be access from presented controller, hence both VCs can access each other. e.g., self.presentedViewController. In order to remove it, one must dismiss controller. So presented controller will release the reference of presenter controller.

Related

Transition from one modal VC to another without delay swift

I have a basic scenario:
I present a VC modally using self.present(, animated:, completion:).
Sometimes due to interactions in this modal VC i need to close one modal and open another one.
So i do the following:
weak var presenter = self.presentingViewController
let newVc = UIViewController()
presenter?.dismiss(animated: true, completion: {
presenter?.present(newVc, animated: true, completion: nil)
})
This works but there is the annoying delay when switching the VC's when user sees the original presenter and can try to interact with it (to open other modals...).
I tried setting animated: false but that doesn't seem to work :/
I can't really switch to UINavigationController model for this because the modals i am presenting themselves are Page View Controllers and have the whole hierarchy of dependent views; the user is never going 'back'; so i'd really like to just present the new modal as quickly as possible...
Update My question is not about how to control or choose the animation. My questions is about having no delay between the modals.
The built-in view controller architecture that switches views with no transition is the tab bar controller. So just turn your view controller into a tab bar controller — with no visible tab bar! To change to the other view controller just change tabs (in code). The change is instant.
This screencast makes it clear that this works as described. We present a view controller (yellow). Then we switch back and forth between two view controllers (green and yellow) as the presented view controllers, instantly. Finally, we dismiss whichever one (green or yellow) is showing. I'm doing it all with simple buttons but that's just for the demo; obviously you could do this however you like. It's the architecture that's the important thing.
I can think only of solutions which would require you to handle the animations yourself
create custom modal transition using UIViewControllerTransitionCoordinator
add your controllers to container views as suggested by #muhammed-gül
present newVC over self and dismiss all presented controllers when you're done
And just a tip, you don't always need to wait for the dismiss completion closure, you can call this and it usually works, but still the underlying viewController is visible.
dismiss(animated: true)
present(newVC, animated: true)

Present 2 navigationControllers in one stack in one go

current i am developing this app and i have the main and login screen.
The architecture works in such a way that when the app launches, the main screen will always present first.
then, if the user is not logged in, the login screen will be presented modally on top of the main screen. (i think this is a normal approach right?).
However, the thing is now that, whenever i do the following code.
self.present(mainNavigationController, animated: false, completion: {
let storyboard = UIStoryboard(name: "LoginSignUp", bundle: nil)
let loginNavigationController = storyboard.instantiateViewController(withIdentifier: "loginNavigationViewController") as! UINavigationController
mainNavigationController.present(loginNavigationController, animated: false, completion: nil)
})
I will always see a blank white main screen before the the login screen is shown, that is kinda ugly.. Anyone has any solution such that these two view controllers are stacked on top of each other from the very beginning and shown once, rather than shown in sequence?
You code is trying to accomplish this:
Present main navigation controller modally over the current view controllers navigation.
Then after showing it present login modally on mainNavigation controller.
You need to change in this way:
Push your main screen in current navigation stack by pushViewController.
And then try to present login screen modally over the current navigation stack.

Dismiss presented view controller, after the presenting view controller has been released

I am working on some old code that I didn't write, and it's really not architected well...
The situation is that a view controller presents a custom view controller modally, however every 30 seconds the presenting view controller is recreated.
The issue here is that if the modal is on screen when this happens, then any effort to dismiss it results in odd behaviour (such as a white screen).
I have tried calling [self.presentedViewController dismissViewControllerAnimated]; on the newly recreated controller, but presentedViewController is nil as you would expect.
I have also tried keeping a weak reference to the modal view controller, then when the presenting VC is reloaded, setting this value to that of the old VC. This has allowed me to call self.customModalVC dismissViewControllerAnimated]; but this is causing the aforementioned white screen, perhaps because it's presenting VC is no longer in the stack?
Any and all suggestions appreciated.
Try passing the navigation controller to newly presented ViewController:
presentedVC.navigation = self.navigationController
Add this to newly created one for dismissing
self.dismiss(animated: false) {
_ = self.navigation?.popViewController(animated: true)
}

How to present VC modally then segue to a VC that's embedded in a Navigation Controller

My app flow is like this:
(1) The app launches you into a LogInViewController that is embedded in a NavigationController.
(2) Inside LogInViewController if runCount < 1 I want to present a set of tutorials VCs that are not embedded in a nav stack.
(3) You can tap "skip" or after swiping through the tutorial VCs you tap an "OK" button, all of which segue you back to LoginViewController.
The problem is that when you are segued back to LogInViewController there's no NavigationController.
What's the best way to approach this?
The answer is really simple, rather than wiring up the buttons to my LogInViewController all I needed to do was wire them up to the NavagationController instead since it presents the LogInViewController

"Present Modally" does not show when another modal is already presented

In my iOS application, my VC is presenting a modal (A) via code.
However, when I already have another modal presented (B), this one is not showing at all.
However, when (A) is deinitted, I see that (B) also gets deinitted.
How can I make sure that (B) always gets shown, no matter what, and in front of all other modals?
performSegueWithIdentifier(SEGUES.SegueTabBarToBroadcast, sender: view )
My TabBarViewController is calling this segue. (The segue is modal according to storyboard).
The problem occurs when one of the view controllers in my TabBar presents a modal. Then, when I try to call performSegueWithIdentifier, the modal doesn't show (but yet deinits when I close the other modal).
I just want this modal to present NO MATTER WHAT. This modal should overlap all other modals.
I also tried this, but the problem persists:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let bvc = storyboard.instantiateViewControllerWithIdentifier("BroadcastViewController") as! BroadcastViewController
self.presentViewController( bvc , animated: true, completion: nil)
Presenting multiple view controllers as a modal is not good practice. If you want to present your vc no matter what, then you have to understand the hierarchy of your view controllers. Shortly, you can present view controller modally on the vc with view that has a window, and when you have already presented any vc modally, your view controller's view that has presented the vc does not have the window, thus can't present other view controller modally. Conclusion: you can present vc modally from the top-most vc. So, solution would be keeping reference to the top-most vc, and presenting the desired vc from that vc. Another solution would be adding vc's view directly to the main window of the app, but I would not recommend solving your problem that way. Hope, this helps.

Resources