Tpixelminer
Tpixelminer

Reputation: 41

Container view function not calling in parent view

I'm trying to run a function in a container view that I added in the storyboard editor but when I call it in the parent view controller, nothing happens. I want to be able to call a function and change a property of the child view controller triggered from the parent. Am I doing something wrong or should I just be doing this another way?

TLDR: Trigger a function in a child view controller from parent

Parent View Controller:

//  ViewController.swift
import UIKit
class ViewController: UIViewController {

    @IBOutlet weak var routeConfirmationView: UIView! //This is the container view that I'm trying to work with
    var RouteSelectionViewController: RouteSelectionViewController?

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(routeConfirmationView)
        
        self?.RouteSelectionViewController?.getRidOfLoadingCover(isHidden: true) //The code that isn't doing anything
    }

}

Container View Controller:

import UIKit

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
        }
    }
    
}

Storyboard: enter image description here

Upvotes: 1

Views: 752

Answers (2)

DonMag
DonMag

Reputation: 77690

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?()
    }
    
}

Upvotes: 3

Andreas Oetjen
Andreas Oetjen

Reputation: 10209

I guess you did not set the RouteSelectionViewController variable (btw., variable names should start with a small letter), so it is nil and nothing happens.

If you want you embed a view controller into another, you need to implement the view controller containment requirements (see documentation).

Upvotes: 0

Related Questions