How can I access data from a container view from the parent view controller in swift?
To gain access to the container view from your parent, you will have to pass a reference from the container view to the parent and then use it in the parent view controller, there are many ways to do that and here is one of them.
In your viewDidAppear
of InfoRegisterController
which is the container view controller add the following code, this method will get a reference of InfoRegisterController
into the parent to be used.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let signUpControllerParent = self.parent as! SignUpController
signUpControllerParent.saveContrainerViewRefference(vc: self)
}
Now in SignUpController
add a local variable for the coming reference to be saved and used later to get the data from the textfields.
var infoRegisterRefferenceVC : InfoRegisterController?
Add this method also in your parent SignUpController
func saveContrainerViewRefference(vc:InfoRegisterController){
self.infoRegisterRefferenceVC = vc
}
Now you can have access to all the textfields and the methods in the container view from the parent for example:
var fullNameTextField = self.infoRegisterRefferenceVC.fullName.text
This should be it :)
Pass values from container view to parent view controller
Steps to do that.
Your container view must contain a embed segue to the child view controller, name that segue something like this.... "homeToContainer" (See the attached Image)
Add this method to your parent View controller (DiaryEntryViewController )
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? ChildViewController,
segue.identifier == "homeToContainer" {
vc.delegate = self
}
}Add Protocol and its variable in ChildViewController:
protocol ChildToParentProtocol:class {
func buttonClickedByUser()
func needToPassInfoToParent(with value:Int)
}
class ChildViewController: UIViewController {
weak var delegate:ChildToParentProtocol? = nil
@IBAction func createTourPressed(_ sender: UIButton) {
// Call here delegate methods to tell parent about the action
delegate?.buttonClickedByUser()
}
}In the last in your parent ViewController, add this Extension:
extension DiaryEntryViewController:ChildToParentProtocol {
func buttonClickedByUser() {
}
func needToPassInfoToParent(with value:Int) {
}
}
Access Container View Controller from Parent iOS
Yes, you can use the segue to get access the child view controller (and its view and subviews). Give the segue an identifier (such as alertview_embed
), using the Attributes inspector in Storyboard. Then have the parent view controller (the one housing the container view) implement a method like this:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSString * segueName = segue.identifier;
if ([segueName isEqualToString: @"alertview_embed"]) {
AlertViewController * childViewController = (AlertViewController *) [segue destinationViewController];
AlertView * alertView = childViewController.view;
// do something with the AlertView's subviews here...
}
}
Call parent View controller function from container view
If you have embedded view controller on another view controller, you can message it's parent view controller with many ways.
- In child (embedded) view controller, you can have reference to parent. Give identifier to the embedding segue in the storyboard, declare
var
with type of the parent in child, and assign the parent onprepare(for segue: UIStoryboardSegue, sender: Any?)
function, and call any public methods of the parent. - Create protocol, make the parent confirm to the protocol, create var of the protocol in child, set parent as protocol object of the child in
prepare(for segue: UIStoryboardSegue, sender: Any?)
, and call protocol methods whenever you want. - Just post notification to
NotificationCenter
on child, and observe the notification on parent. Documentation ofNotificationCenter
, here you can find a brief example of using it.
Hope this helps!
PS: You can also observe properties of the child in the parent vc, if you want that way, I can explain.
From within a view controller in a container view, how do you access the view controller containing the container?
You can use the prepareForSegue
method in Vc1 as an embed segue occurs when the ContainerViewController is made a child. you can pass self as an obj or store a reference to the child for later use.
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSString * segueName = segue.identifier;
if ([segueName isEqualToString: @"embedseg"]) {
UINavigationController * navViewController = (UINavigationController *) [segue destinationViewController];
Vc2 *detail=[navViewController viewControllers][0];
Vc2.parentController=self;
}
}
Edit: minor code fix
How to pass data from parent view controller to child container view controller
You can try it more early like
let childVC = storyboard!.instantiateViewController(withIdentifier: "ChildVC") as! ChildVC
childVC.boolVariable = true
Accessing parent view buttons in container view controller
One option is to use NotificationCenter
, have your buttons post the notification, and have your child view controller listen for them.
For example, in the parent VC, post the notification in the function called when a button is tapped, like so:
@IBAction func buttonTapped(_ sender: UIButton) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "ButtonTapped"), object: nil, userInfo: nil)
}
In the child VC that needs to respond to the button tap, place the following code in viewWillAppear:
to set the VC as a listener for that specific notification:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(handleButtonTap(_:)), name: NSNotification.Name(rawValue: "ButtonTapped"), object: nil)
}
In the same view controller, add the handleButtonTap:
method mentioned above. When the "ButtonTapped" notification comes in, it will execute this method.
@objc func handleButtonTap(_ notification: NSNotification) {
//do something when the notification comes in
}
Don't forget to remove the view controller as an observer when it is no longer needed, like this:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
Container view function not calling in parent view
To call functions, or access properties, in a View Controller embedded in a Container View, you need to get and keep a reference to that controller.
When the Container View loads the embedded VC, it calls Prepare For Segue. Grab your reference there:
class WithContainerViewController: UIViewController {
var routeSelectionVC: RouteSelectionViewController?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? RouteSelectionViewController {
// save reference to VC embedded in Container View
self.routeSelectionVC = vc
}
}
@IBAction func didTap(_ sender: Any) {
if let vc = routeSelectionVC {
vc.getRidOfLoadingCover(isHidden: true)
}
}
}
class RouteSelectionViewController: UIViewController {
@IBOutlet weak var loadingCoverView: UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
}
//The function that I want to trigger from the other view controller:
func getRidOfLoadingCover (isHidden: Bool){
if (isHidden == true) {
loadingCoverView.alpha = 0
}
else if (isHidden == false) {
loadingCoverView.alpha = 100
}
}
}
You will likely next ask about calling a function in the "parent" VC from the embedded VC. This can be done with protocol / delegate pattern, or with closures. Again, you can set that up in prepare for segue:
class WithContainerViewController: UIViewController {
var routeSelectionVC: RouteSelectionViewController?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? RouteSelectionViewController {
// set the closure in the VC embedded in Container View
vc.callbackClosure = {
self.routeSelectionButtonTapped()
}
// save reference to VC embedded in Container View
self.routeSelectionVC = vc
}
}
@IBAction func didTap(_ sender: Any) {
if let vc = routeSelectionVC {
vc.getRidOfLoadingCover(isHidden: true)
}
}
func routeSelectionButtonTapped() -> Void {
print("Button in RouteSelectionViewController in Container View was tapped!")
}
}
class RouteSelectionViewController: UIViewController {
@IBOutlet weak var loadingCoverView: UIActivityIndicatorView!
var callbackClosure: (() -> ())?
override func viewDidLoad() {
super.viewDidLoad()
}
//The function that I want to trigger from the other view controller:
func getRidOfLoadingCover (isHidden: Bool){
if (isHidden == true) {
loadingCoverView.alpha = 0
}
else if (isHidden == false) {
loadingCoverView.alpha = 100
}
}
@IBAction func didTap(_ sender: Any) {
callbackClosure?()
}
}
How to access the child view controller from parent view controller in swift?
The answer is ... (drum-roll......) ... it depends.. :-)
NSViewController
& UIViewController
have a .parent
property.
https://developer.apple.com/documentation/uikit/uiviewcontroller/1621362-parent
https://developer.apple.com/documentation/appkit/nsviewcontroller/1434491-parent
However, it is only populated if you're implementing the container-view-controller design pattern: https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html (many uikit components use this pattern) IE:
aViewController.addChild(bViewController)
bViewControler.didMove(toParent: aViewController)
bViewController.parent // is aViewController
*Note: you'll have to manage the view stack yourself, this just ensures things like the lifecycle/drawing/resize/etc handlers happen in the correct order
If you need to retain a reference to a view controller (child or otherwise), create a property on the child and set a reference to it, or use the container-view-controller design, it's very useful.
Cheers
- J
Related Topics
How to Throttle Search (Based on Typing Speed) in iOS Uisearchbar
Multiple Uilabels Inside a Self Sizing Uitableviewcell
Document Directory Path of Xcode Device Simulator
How to Get the Font Name from an Otf or Ttf File
In iOS 12, When Does the Uicollectionview Layout Cells, Use Autolayout in Nib
How to Simultaneously Satisfy Constraints - No Constraints in Place
Differencebetween Pan and Swipe in iOS
iOS 7 Status Bar Collides with Navigationbar
Get Device Location (Only Country) in iOS
How to Use Avfoundation to Crop a Video
How to Turn a Cvpixelbuffer into a Uiimage
What Is the Second Parameter of Nslocalizedstring()
Uicollectionview's Cell Disappearing
Autolayout Is Ignored in Custom Uitableviewcell
The Executable Gets Signed with Invalid Entitlements in Xcode