viewDidload and viewDidAppear not being called? - ios

I have 3 view controllers and a container view controller. I add those 3 view controllers as child view controllers in the container. When I launch the app I have print statements in viewDidload and viewDidAppear in all the view controllers which get executed.
The problem is: When I "scroll" back on those views and it "appears" again the print statements do not execute nor any code inside viewDidAppear nor viewDidLoad. Why is this happening?
Here is my code where I instantiate my view controllers. Thanks for the help!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
let storyboard = UIStoryboard(name: "Main", bundle: nil)
page1 = storyboard.instantiateViewController(withIdentifier: StoryboardIdentifiers.feedViewController.rawValue) as! FeedViewController
page1.view.translatesAutoresizingMaskIntoConstraints = false
page1.delegate = self
scrollView.addSubview(page1.view)
addChildViewController(page1)
page1.didMove(toParentViewController: self)
page2 = storyboard.instantiateViewController(withIdentifier: StoryboardIdentifiers.favoritesViewController.rawValue) as! FavoritesViewController
page2.view.translatesAutoresizingMaskIntoConstraints = false
page2.delegate = self
scrollView.addSubview(page2.view)
addChildViewController(page2)
page2.didMove(toParentViewController: self)
page3 = storyboard.instantiateViewController(withIdentifier: StoryboardIdentifiers.settingsViewController.rawValue) as! SettingsViewController
page3.view.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(page3.view)
addChildViewController(page3)
page3.didMove(toParentViewController: self)
}

What would trigger those view controllers to cycle through their life cycles?
The parent view controller, whatever it's named will run through it's load cycle. All views will also run through their. (I bet if you subclass a view and, using it, put a breakpoint inside draw(rect:) it would hit it.) But there's nothing to trigger the child view controllers to do their thing.
From what I see, your view hierarchy is:
Main view
Scroll view inside main view
Three page views inside scroll view
When the main view (the afore-mentioned parent view controller) loads, it goes through the usual viewDidLoad, viewWillAppear, viewWillLoadSubviews.... and it's there that all of the above views get loaded, laid out, and drawn.
Nothing is happening to trigger those three page controllers to do any loading.

Related

Adding a dependencies to a child view controller

I want to present a custom view controller within a navigation controller within modal view. To do this I made a view in interface builder, added a container view, and embedded the contained view in a navigation controller. The contained view is my custom view controller, DetailViewController.
I have to add dependencies to the DetailViewController object to at runtime. Here’s the method where I’ll be presenting the DetailViewController:
override func tableView(_: UITableView, didSelectRowAt: IndexPath) {
guard let record = records[didSelectRowAt.row] else { return }
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let containerView = storyBoard.instantiateViewController(withIdentifier: "DetailContainer")
containerView.modalPresentationStyle = .overFullScreen
self.present(detailContainer, animated: true, completion: nil)
}
How can I add the record to DetailViewController? I tried to access children of the container view, but the array is empty. This Apple document says
The children must be instantiated at the same time as the parent so that the appropriate parent-child relationships can be created.
I'm not sure how to achieve that.
containerView.children is empty because viewcontroller's view isn't loaded.
You can force to load view by calling containerView.view thereafter containerView.children will exist.

How to call a viewcontroller in other class using KGModal

I'm working on an app. The app is in the swift. Now the problem is I'm trying to represent a view controller from another view using the KGModel.
Lets say that are two view controller ViewA and ViewB. Now if i set the viewB as the initial viewcontroller then it's working fine. All the delegate of the tableview controller called successfully but if try to call the ViewB from viewA then the table view always return empty. Is any one know how to call the other view controller in the current view using KGmodel. Thanks in advance.
Code To Call ViewB from ViewA
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "MoveToReviewView") as? ReviewViewController
controller?.assignValue = self
presentController(controller!)
func presentController(_ controller: UIViewController) {
let ret = self.view.frame
controller.view.frame.size.width = ret.size.width - ret.size.width/4
controller.view.frame.size.height = ret.size.height/2
KGModal.sharedInstance().show(withContentView: controller.view, andAnimated: true)
}
The output is

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")

add subview over UITableView

First of, I am noob to Swift programming.
I am trying to show a custom view over a UITableView.
I am facing two major issues :
a) The subview does not appear correctly firstly. ref image below :
and after few moments actual view is loaded :
b) After the UITableView is scrolled, the view is not coming over the current top scroll position of UITableView
Following is the code to add subview :
let vaAdPopupViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "AdPopupWithCrossViewController") as! AdPopupWithCrossViewController
vaAdPopupViewController.adID = adID
vaAdPopupViewController.tableView = self.tableView
if let message = parseJSON["adv_text"] as? String{
vaAdPopupViewController.message = message
}
let navigationBarFrame: CGRect = (self.navigationController?.view.frame)!
let frameSize = CGRect(x: navigationBarFrame.minX, y: navigationBarFrame.minY, width: navigationBarFrame.width, height: (navigationBarFrame.height - (self.navigationController?.navigationBar.frame.size.height)!))
vaAdPopupViewController.view.frame = frameSize
self.tableView.addSubview(vaAdPopupViewController.view)
vaAdPopupViewController.view.tag = 1000
self.addChildViewController(vaAdPopupViewController)
vaAdPopupViewController.didMove(toParentViewController: self)
also in AdPopupWithCrossViewController :
override func viewDidLoad() {
self.view.superview?.layoutIfNeeded()
self.view.layoutIfNeeded()
super.viewDidLoad()
}
Please guide me how to resolve this issue.
Thank You.
You probably want to either create a Present Modally Segue or use present() via code.
You've already created your AdPopupWithCrossViewController. Set its background color to be translucent. Then you can present it like this:
let vaAdPopupViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "AdPopupWithCrossViewController") as! ModalOverTableViewController
vaAdPopupViewController.modalPresentationStyle = .overCurrentContext
self.present(vaAdPopupViewController, animated: true, completion: nil)
Then, your little "X" button can remove the ad with:
#IBAction func closeTapped(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
You can try out the various options on .modalPresentationStyle and .modalTransitionStyle, as well as setting animated to true or false, to get the appearance / behavior you desire.
As Dan says, you should add your popup as a subview of the view controller's view, not of the table view. A Table view's view hierarchy is private and you should not be trying to mess with it.
Note that you can't do this with a table view controller. This has always bugged me, but it's a fact: A UITableViewController manages a single table view and nothing else. If you want a more complex view hierarchy you need to embed your table view controller in another view controller. I do this with a container view and an embed segue, which is very easy.
If you do that then you can add your new view controller's content to the parent view controller's content view, not to the table view controller's view (or to the table view itself)

UINavigationController Within UIPageViewController Issue

I've searched and searched still cannot figure out how to fix my problem. I have a UIPageviewController as the initial view controller (like Tinder style). I want each viewController child (page) to be embedded within their own UINavigationController, so basically the page view controller will add the UINavigationController as it's child view controller. And I'm using the setViewController method when a user taps a button in it's child view controller's navigation controller to move to the next view controller by getting a reference to the parent pageviewcontroller, as opposed to using the pageviewcontroller datasource. I don't want to use the pageviewcontroller's datasource because I don't want the swiping gesture.
However, when the user taps the button in the child's navigation controller to trigger it's parent pageviewcontroller to set the next controller, which is also a UINavigationController, the animation of doing this makes the whole screen jump up and then down. If I remove the navigation controller and just send the view controller child instead, then it works fine. Does anyone know why embedding a navigation controller inside a pageviewcontroller would cause this issue?
Here's the code used when a user taps the bar button item in the navigation controller's navigation bar:
func pageViewControllerSetNewControllerFoward() {
print("page view controller set matches")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let matchesController = storyboard.instantiateViewController(withIdentifier: "matchesNav") as! UINavigationController
parentPageViewControllerReference.setViewControllers([matchesController], direction: .forward, animated: true, completion: nil)
}
The likely culprit of this behaviour is the UINavigationControllertrying to set it's own UINavigationBar. Try setting the
self.navigationController?.setNavigationBarHidden(true, animated: false)
in the viewDidLoad() of your UINavigationController
This can be solved by setting Automatically Adjust Scroll Views to false for the PageViewController and NavigationViewControllers.
Do so by self.pageViewController.automaticallyAdjustsScrollViewInsets = false or easier still in Interface Builder under attributes>layout>Adjust Scroll View Insets set to false.

Resources