Children view controllers must have a common parent view controller in swift

37 Views Asked by At

I have created one container view . Here I'm adding two view controller content into single view controller. I am rendering the view based on the different state but I want to combine both view content into single view .. The code is compile but produce following error ..

Thread 1: "Children view controllers <PremierSwift.LoadingViewController: 0x100f1f1a0> and <UIViewController: 0x104850c90> must have a common parent view controller when calling -[UIViewController transitionFromViewController:toViewController:duration:options:animations:completion:]"

Here is the code I have modified..

private func showMovieDetails(_ movieDetails: MovieDetails) {
        let containerView = UIViewController()
        let displayViewController = MovieDetailsDisplayViewController(movieDetails: movieDetails)
        let smiliarMovieViewController = SmiliarMovieViewController(viewModel: viewModel)
        containerView.addChild(smiliarMovieViewController)
        containerView.addChild(displayViewController)
        displayViewController.view.frame = view.bounds
        displayViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        smiliarMovieViewController.view.frame = view.bounds
        smiliarMovieViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
      
        containerView.willMove(toParent: nil)
        transition(
            from: currentViewController,
            to: containerView,
            duration: 0.25,
            options: [.transitionCrossDissolve],
            animations: nil
        ) { (_) in
            self.currentViewController.removeFromParent()
            self.currentViewController = containerView
            self.currentViewController.didMove(toParent: self)
        }
    }

Here is the complete view controller code..

final class MovieDetailsViewController: UIViewController {

    private let viewModel: MoviesDetailsViewModel
    private var currentViewController: UIViewController!
    
    init(viewModel: MoviesDetailsViewModel) {
        self.viewModel = viewModel
        super.init(nibName: nil, bundle: nil)
        navigationItem.largeTitleDisplayMode = .never
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.leftBarButtonItem = UIBarButtonItem.backButton(target: self, action: #selector(didTapBack(_:)))
        updateFromViewModel()
        bindViewModel()
        viewModel.fetchData()
    }

    private func bindViewModel() {
        viewModel.updatedState = { [weak self] in
            guard let self else { return }
            DispatchQueue.main.async {
                self.updateFromViewModel()
            }
        }
    }

    private func updateFromViewModel() {
        let state = viewModel.state
        title = state.title
        switch state {
        case .loading(let movie):
            self.showLoading(movie)
        case .loaded(let details):
            self.showMovieDetails(details)
        case .error:
            self.showError()
        case .pageLoaded(let page):
            self.showSimiliarMovieDetails(page)
        }
    }

    private func showLoading(_ movie: Movie) {
        let loadingViewController = LoadingViewController()
        addChild(loadingViewController)
        loadingViewController.view.frame = view.bounds
        loadingViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(loadingViewController.view)
        loadingViewController.didMove(toParent: self)
        currentViewController = loadingViewController
    }

    private func showMovieDetails(_ movieDetails: MovieDetails) {
        let containerView = UIViewController()
        let displayViewController = MovieDetailsDisplayViewController(movieDetails: movieDetails)
        let smiliarMovieViewController = SmiliarMovieViewController(viewModel: viewModel)
        containerView.addChild(smiliarMovieViewController)
        containerView.addChild(displayViewController)
        displayViewController.view.frame = view.bounds
        displayViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        smiliarMovieViewController.view.frame = view.bounds
        smiliarMovieViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
      
        containerView.willMove(toParent: nil)
        transition(
            from: currentViewController,
            to: containerView,
            duration: 0.25,
            options: [.transitionCrossDissolve],
            animations: nil
        ) { (_) in
            self.currentViewController.removeFromParent()
            self.currentViewController = containerView
            self.currentViewController.didMove(toParent: self)
        }
    }
    
    private func showSimiliarMovieDetails(_ similiarMovieDetails: Page<Movie>) {
        let smiliarMovieViewController = SmiliarMovieViewController(viewModel: viewModel)
        addChild(smiliarMovieViewController)
        smiliarMovieViewController.view.frame = view.bounds
        smiliarMovieViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        currentViewController?.willMove(toParent: nil)
        transition(
            from: currentViewController,
            to: smiliarMovieViewController,
            duration: 0.25,
            options: [.transitionCrossDissolve],
            animations: nil
        ) { (_) in
            self.currentViewController.removeFromParent()
            self.currentViewController = smiliarMovieViewController
            self.currentViewController.didMove(toParent: self)
        }
    }

    private func showError() {
        let alertController = UIAlertController(title: "", message: LocalizedString(key: "moviedetails.load.error.body"), preferredStyle: .alert)
        let alertAction = UIAlertAction(title: LocalizedString(key: "moviedetails.load.error.actionButton"), style: .default, handler: nil)
        alertController.addAction(alertAction)
        present(alertController, animated: true, completion: nil)
    }

    @objc private func didTapBack(_ sender: UIBarButtonItem) {
        navigationController?.popViewController(animated: true)
    }
}

Here is the screenshot of the error.

enter image description here

0

There are 0 best solutions below