Difference between viewControllers and childViewControlle for UINavigationController - ios

fileprivate func test() {
guard let w = self.view.window else {
print("no window")
return
}
guard let rootvc = w.rootViewController as? UINavigationController else {
print("no rootvc")
return
}
for vc in rootvc.childViewControllers {
print("CHILD \(vc)")
}
for vc in rootvc.viewControllers {
print("VC \(vc)")
}
}
the code above shows the same. But whats the difference between childViewControllers and viewControllers ?

According to documentation:
public var childViewControllers: [UIViewController] { get }
childViewControllers: An array of view controllers that are children of the current view controller. (read-only). This property does not include any presented view controllers. This property is only intended to be read by an implementation of a custom container view controller.
var viewControllers: [UIViewController] { get set }
viewControllers: The view controllers currently on the navigation stack.
NOTE: A ViewController also have childViewControllers property. but viewControllers property defined in UINavigationController.

ViewControllers are The view controllers currently on the navigation stack. Where ChildViewControllers are An array of view controllers that are children of the current view controller.
The root view controller is at index 0 in the array, the back view controller is at index n-2, and the top controller is at index n-1, where n is the number of items in the array.
Assigning a new array of view controllers to this property is equivalent to calling the setViewControllers:animated: method with the animated parameter set to false.
ChildViewControllers property does not include any presented view controllers. This property is only intended to be read by an implementation of a custom container view controller.
You can easily get description about it by Alt + Click on syntax!!

Related

How to pass data to a embedded UIViewController in side a UIView - Swift 5

There's a view controller B. So, have embedded B as child view controller in viewController A in a UIView. Now, need to call a api in child view controller B when it is added as a child. So, need to set a check when added B as child only then this api need to be hit. Kindly help in this.
Below is the code, how i embedded B as child View in A viewController:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vcController: UIViewController = storyboard.instantiateViewController(withIdentifier: "BNameViewController") as! BNameViewController
//add as a childviewcontroller
addChild(vcController)
// Add the child's View as a subview
viewBList.addSubview(vcController.view)
vcController.view.frame = viewBList.bounds
vcController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// tell the childviewcontroller it's contained in it's parent
vcController.didMove(toParent: self)
viewBList is the UIView in View controller A.
So, now need in this case an api to be called in VC B not when we navigate to B from any other VC. I tried passing a bool or string by declaring same in VC B and the pass value from A, that doesn't work. Please guide. Hope i made my question clear, please feel free to ask if any doubt.
There are so many ways to do this, When you are navigating to view controller B from some other view controller then you have navigationController property not nil.
In that case you can check like that
override func viewDidLoad(animated: Bool) {
super.viewDidLoad(animated: animated)
//If navigating from some view controller then
if self.navigationController != nil {
//Code here for case, when you are navigating from some one
}
//View controller is child of someone
if (self.navigationController == nil || self.presentingViewController == nil || self.parent != nil ) {
//This is your case,
// hit api here
}
}

iOS (Swift): Presenting View Controller Embedded in Navigation Controller

I have a UIViewController (AVC) that is embedded in a UINavigationController. AVC (present modally) segues to another UIViewController (BVC). Inside BVC, the variable self.presentingViewController is of type an optional NavigationController rather than a AVC as I would have expected.
I have to downcast the first childViewControllers as an AVC as follows:
let pvc = self.presentingViewController
if let avc = pvc?.childViewControllers.first as? AVC {
// ...
}
Why is self.presentingViewController not as I expected it to, i.e. an AVC?
Many thanks.
To access it
if let pvc = self.presentingViewController as? UINavigationController {
if let avc = pvc.viewControllers.first as? AVC {
// ...
}
}
//
From Docs
When you present a view controller modally (either explicitly or
implicitly) using the present(_:animated:completion:) method, the view
controller that was presented has this property set to the view
controller that presented it. If the view controller was not presented
modally, but one of its ancestors was, this property contains the view
controller that presented the ancestor. If neither the current view
controller or any of its ancestors were presented modally, the value
in this property is nil.

UIPageViewController viewControllers always return a single controller

I have two view controllers inside a UIPageViewController. I need to get all view controllers inside the UIPageViewController to call methods inside them, but it always returns a single page only (either the first page or the second page).
The code is below for convenience:
if let viewControllers: [UIViewController] = self.viewControllers {
print(viewControllers)
for controller in viewControllers {
if let firstController: FirstViewController = controller as? FirstViewController {
//Call something
}
if let secondController: SecondViewController = controller as? SecondViewController {
//Call something
}
}
}
In fact, it returns only the visible view controller inside the page controller.
This is intended behaviour.
In a simple UIPageViewController, this array will only return the currently visible view controller(s), which is usually just one view controller.
Keep in mind that UIPageViewController heavily caches and reuses controllers, just like a UITableViewController would. You may want to reflect changes in another way.

Is there a way to find out whether a view controller is popped off the navigation stack?

Im trying to detect when a view controller is popped off the navigation stack, in a way that i have a reference to the controller on the next layer of the stack (currently working with Swift 3). Thanks
UINavigationController has a property viewControllers that contains an array of the view controllers currently on the stack. You could get the array of view controllers and then fetch the next-to-last view controller from that array:
guard let navController = self.navigationController else {
print("We are not part of a navigation stack!")
return
}
let stack = navController.viewControllers
let stackCount = stackCount
if stackCount > 1 {
let nextVC = viewControllers[stackCount - 2]
//nextVC now contains the view controller one down from the current VC
} else {
//We are the root view controller
}

In my root controller, how do I check if there's a child controller?

My root controller performs push segues to some child controllers.
In my root controller, I want to check whether there's a controller on top of self and that child controller is of type "MessageViewController"
How can I perform that check in Swift?
self.navigationController.viewControllers.count will tell you how many controllers are on the stack. If you're interested in the one directly above you, you can test if self.navigationController.viewControllers[1] (after checking that there are at least 2 controllers on the stack) is a MessageViewController.
if self.navigationController!.viewControllers.count >= 2 {
let vc = self.navigationController!.viewControllers[1] as! UIViewController
if vc is MessageViewController {
// do whatever
}
}
If the segues are modal presentations, you can check if the presentedViewController property is non nil,
if let vc = self.presentedViewController {
if vc is MessageViewController {
// do whatever
}
}else{
println("No presented view conttoller")
}

Resources