Asim Iftikhar Abbasi
Asim Iftikhar Abbasi

Reputation: 617

viewDidAppear being called strangley

I have a viewController containing segmentedControl. I have a VCA and VCB which are in the segmentedControl. When I tap on second segment VCB appears. Now I am pushing another ViewController from VCB. But when coming back from that viewController, viewDidAppear of VCA is being Called. Which is strange to me. Because user is on the VCB so why the viewWillAppear and viewDidAppear of VCA are being called ? Here is a diagram to explain more

enter image description here

This is how I am adding viewControllers to segmentedControl

 func switchToViewController(viewController: UIViewController, selectedIndex: Int) {

    viewController.removeFromParentViewController()
    viewController.view.removeFromSuperview()

    addChildViewController(viewController)
    viewController.view.translatesAutoresizingMaskIntoConstraints = false
    self.view.addSubview(viewController.view)

    // Setting constraints of the container view
    NSLayoutConstraint.activate([
    viewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0),
        viewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0),
        viewController.view.topAnchor.constraint(equalTo: view.topAnchor, constant: 50),
        viewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0)
        ])

    viewController.didMove(toParentViewController: self)
}

I am just unable to understand the behavior. So please guide me.

Upvotes: 2

Views: 343

Answers (2)

Karthick Selvaraj
Karthick Selvaraj

Reputation: 2505

Here you go, you can achieve this by using containerView. ContainerView is a normal UIView subclass. Your UI will be like this. You will have one baseViewController where you will have segmentControl and containerView view in baseViewController.

enter image description here

Assume you have two view controller namely viewController1 and viewController2. You can add these viewControllers as childViewController to this containerView like below.

import UIKit

class BaseViewController: UIViewController {

    @IBOutlet weak var typeSegment: UISegmentedControl!
    @IBOutlet weak var containerView: UIView!

    var viewController1: UIViewController?
    var viewController2: UIViewController?


    // MARK: - Action method.

    @IBAction func segmentIndexChanged(_ sender: Any) {

        let selectedIndex = typeSegment.selectedSegmentIndex

        switch selectedIndex {
        case 0:
            addVC1()
        case 1:
            addVC2()
        default:
            break
        }

    }

func rectForChildVC() -> CGRect {

    let rect = CGRect(x: containerView.frame.origin.x , y: containerView.frame.origin.y, width: containerView.frame.size.width, height: containerView.frame.size.height)
    return rect

}

func addVC1() {

    removeVC2()
    let storyboard = UIStoryboard(name: "StoryboardName", bundle: nil)
    viewController1 = storyboard.instantiateViewController(withIdentifier: "Viewcontroller1Identifier") // Create you first view controller instance here.
    viewController1?.view.frame = rectForChildVC()
    addChildViewController(viewController1!)
    view.addSubview((viewController1?.view)!)
    viewController1?.didMove(toParentViewController: self)
    view.layoutIfNeeded()

}

func addVC2() {

    removeVC1()
    let storyboard = UIStoryboard(name: "StoryboardName", bundle: nil)
    viewController2 = storyboard.instantiateViewController(withIdentifier: "Viewcontroller2Identifier") // Create you second view controller instance here.
    viewController2?.view.frame = rectForChildVC()
    addChildViewController(viewController2!)
    view.addSubview((viewController2?.view)!)
    viewController2?.didMove(toParentViewController: self)
    view.layoutIfNeeded()

}

func removeVC1() { // Remove first view controller.

    if let viewController = viewController1 {
        viewController.didMove(toParentViewController: nil)
        viewController.view.removeFromSuperview()
        viewController.removeFromParentViewController()
    }

}

func removeVC2() { // Remove second view controller

    if let viewController = viewController2 {
        viewController.didMove(toParentViewController: nil)
        viewController.view.removeFromSuperview()
        viewController.removeFromParentViewController()
    }

}

}

Thanks.

Upvotes: 1

DonMag
DonMag

Reputation: 77672

You are never removing the current view controller and its view from the hierarchy...

You need to keep track of which VC/view is currently displayed - perhaps with a currentVC variable, and your function should look something like this:

func switchToViewController(viewController: UIViewController, selectedIndex: Int) {

    // remove current ViewController from VC hierarchy
    currentVC.removeFromParentViewController()

    // remove current VC.View from View hierarchy
    currentVC.view.removeFromSuperview()

    // the "incoming" ViewController becomes the "current" ViewController
    currentVC = viewController

    addChildViewController(viewController)
    viewController.view.translatesAutoresizingMaskIntoConstraints = false
    self.view.addSubview(viewController.view)

    // Setting constraints of the container view
    NSLayoutConstraint.activate([
    viewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0),
        viewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0),
        viewController.view.topAnchor.constraint(equalTo: view.topAnchor, constant: 50),
        viewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0)
        ])

    viewController.didMove(toParentViewController: self)
}

Upvotes: 2

Related Questions