Swift 4 Call ViewWillAppear after dismissing View Controller - ios

I would like to call viewWillAppear after dismissing a layover ViewController.
ViewController1 -> Segue -> ViewController2
In VeiwController2
1.)
self.dismiss(animated: true, completion: nil)
2.)
override func viewDidDisappear(_ animated: Bool) {
ViewController1().viewWillAppear(true)
}
In VeiwController1
When viewWillAppear is called im getting null errors crashing my app. How can i dismiss a overContext ViewController and call the viewWillAppear method in a correct manner.

viewWillAppear is called automatically when you dismiss VC2. Delete:
ViewController1().viewWillAppear(true)
Try deleting:
super.viewWillAppear(animated) in VC1.
viewDidAppear not getting called
Does it even go back to your VC? self.dismiss works with "Present Modally" segue here. Or embed in NavigationBar, with popViewController

// Override this function in ViewController1
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
//Your code here will execute after viewDidLoad() or when you dismiss the child viewController
}
I'd suggest you go through the life cycle of ViewController.
Apple documentation for ViewController life cycle

yout modal should be .fullScreen
Try with this:
let createAccounts = CreateAccounts();
let navController = UINavigationController(rootViewController: createAccounts)
navController.modalPresentationStyle = .fullScreen

Related

Swift initialize tabBarController without presenting it

The initial view controller is the tab bar controller. The tab bar is created programmatically.
Problem:
I need to load the TabBarViewController without presenting it if the boolean value loggedIn == false.
On older devices, this code works fine to never show the TabBarViewController if the user is not logged in.
However, on newer/faster devices the tab bar flashes before presenting the LogInViewController().
final class TabBarViewController: UITabBarController {
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
configureTabs()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if(!loggedIn){
let loginVC = LogInViewController()
loginVC.isModalInPresentation = true
loginVC.modalPresentationStyle = .fullScreen
present(loginVC, animated: false)
}
}
}
What is the best work around to still load the TabBarViewController but not show it if I need to present a new VC.

Resetting the navigation stack on a UITabBarController doesn't work

I'm trying to reset the navigation stack on a subclass of UITabViewController embedded in a UINavigationController but it doesn't work.
My navigation stack, which I create programmatically, is like this:
UINavigationController => ControllerA (a subclass of UIViewController) =>
ControllerB (a subclass of UIViewController) => ControllerC (a
subclass of UITabBarController).
When users press on the "Back" button or swipe back from ControllerC, the app should go back to ControllerA, not ControllerB.
Usually, when I want to reset the navigation stack, I do this in the Controller's viewDidLoad() method:
override func viewDidLoad() {
super.viewDidLoad()
// usually work, but not in a subclass of UITabBarController as self.navigationController is nil
if let navigationController = self.navigationController {
// keep only the root controller (0) and the current controller
navigationController.viewControllers = [navigationController.viewControllers[0], self]
}
}
but this doesn't work in ControllerC (the subclass of UITabViewController) as self.navigationController is nil.
If I do this instead (still in ControllerC's viewDidLoad() method):
/// ControllerC's viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
if let navigationController = UIApplication.shared.keyWindow?.rootViewController as? UINavigationController {
// keep only the root controller (0) and the current controller
navigationController.viewControllers = [navigationController.viewControllers[0], self]
}
}
This works, but then there is no animation between ControllerB and ControllerC when I do:
controllerB.navigationController?.pushViewController(ControllerC(), animated: true)
I also tried to override ControllerC's viewWillDisappear() method:
/// ControllerC's viewWillDisappear
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if self.isMovingFromParent {
if let navigationController = UIApplication.shared.keyWindow?.rootViewController as? UINavigationController {
navigationController.popToRootViewController(animated: true)
}
}
This works, but ControllerB is briefly visible before ControllerA is shown.
Any help would be greatly appreciated!
In the ControllerC instead of trying to override viewWillDisappear() method you can override viewDidAppear() like that:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let navC = UIApplication.shared.keyWindow?.rootViewController as? UINavigationController {
// keep only the root controller (0) and the current controller
navC.viewControllers = [navC.viewControllers[0], self]
}
}
And ControllerB won’t be briefly visible before ControllerA when you navigate backwards.

Unable to remove child viewcontroller after Navigation

I have added a child viewcontroller to VC1. On tapping a button in child viewcontroller , I am pushing to another viewcontroller , VC2. On tapping back button in VC2 , I need to remove the child viewcontroller but I m unable to do it.Can u pls help me ?
override func viewDidDisappear(_ animated: Bool) {
let controller = storyboard!.instantiateViewController(withIdentifier: "PopupViewController") as! PopupViewController
controller.willMove(toParentViewController: nil)
controller.view.removeFromSuperview()
controller.removeFromParentViewController()
}
I added the following in VC1 and it solved my problem
override func viewWillDisappear(_ animated: Bool) {
for controllers in self.childViewControllers
{
controllers.willMove(toParentViewController: nil)
controllers.view.removeFromSuperview()
controllers.removeFromParentViewController()
}
}

Does 'pushViewController' Prevent the ViewController from Calling deinit?

I have several view controllers (UIViewController). Each view controller has its own storyboard. And I want the app to call deinit when it transitions from one view controller to another. But it won't.
The app starts with HomeViewController. And it will transition to SelectViewController when the user taps a button (UIButton).
class HomeViewController: BasicViewController {
#IBAction func selectTapped(_ sender: UIButton) {
let storyboard = UIStoryboard(name:"Select",bundle:nil)
let controller = storyboard.instantiateViewController(withIdentifier: "SelectView") as! UINavigationController
let viewController = controller.topViewController as! SelectViewController
self.navigationController?.pushViewController(viewController, animated: true)
}
deinit {
print("HOME HAS BEEN REMOVED FROM MEMORY")
}
}
The app never calls deinit when it leaves HomeViewController. I wonder if that's because it's pushing a view controller? If I set the view controller as follows, the app will crash. What am I doing wrong? I have never done it with different storyboards. Thanks.
class HomeViewController: BasicViewController {
#IBAction func selectTapped(_ sender: UIButton) {
let storyboard = UIStoryboard(name:"Select",bundle:nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "SelectView") as! SelectViewController
self.navigationController?.setViewControllers([viewController], animated: true)
}
}
UPDATE 1
I guess it's just the following.
#IBAction func selectTapped(_ sender: UIButton) {
let storyboard = UIStoryboard(name:"Select",bundle:nil)
let controller = storyboard.instantiateViewController(withIdentifier: "SelectView") as! UINavigationController
self.present(controller, animated: true, completion: nil)
}
UPDATE 2
I also clear the view controller stack when SelectViewController appears as follows.
override func viewWillAppear(_ animated:Bool) {
super.viewWillAppear(animated)
var navigationArray = self.navigationController?.viewControllers
navigationArray?.removeAll()
}
Actually, It is not about storyboards. As per the Apple's documentation, "deinit" method gets automatically called when an object is deallocated from memory, not when a view controller is pushed from current one.
When you push "SelectViewController" from "HomeViewController", instance of "HomeViewController" does not deallocated from memory, hence deinit method does not called.
Here is a link to Apple's Documentation for Deinitialization. Alternatively, you can use "viewDidDisappear" method of the view controller to perform an operation if it satisfies your need.
From your code snippet, I understand that you expect deinit is called after pushViewController. But, by calling pushViewController, your navigation controller pushes your HomeViewContoller to navigation stack, which means navigation controller holds strong reference to your HomeViewController object. So, deinit is not called. If you don't need HomeViewController, you have to manually remove it from navigation stack w/in SelectViewController.
See this how. How to remove a specific view controller from uinavigationcontroller stack?
In SelectViewController,
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let allControllers = NSMutableArray(array: navigationController!.viewControllers)
allControllers.removeObject(at: allControllers.count - 2)
self.navigationController!.setViewControllers(allControllers as [AnyObject] as! [UIViewController], animated: false)
}

Navigation bar is moving up to statusbar

I have a viewController. Which does not have navigationBar. I am pushing another viewController that has navigationBar. Which is going up
I am using following code to show the navigationBar
self.navigationController?.setNavigationBarHidden(false, animated: false)
I believe you trying to hide navigationBar in firstVC and show it in secondVC.
Try following method into your firstVC and make sure you embedded your firstVC with navigationController.
Your storyBoard flow layout should be look like below...
Implement below method in firstVC.
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.setNavigationBarHidden(true, animated: true)
}
override func viewWillDisappear(_ animated: Bool) {
self.navigationController?.setNavigationBarHidden(false, animated: true)
}
Output:Updated

Resources