Skip to content

viewWillDispear is called in unexpected situations #728

@renshi-asada

Description

@renshi-asada

Since this commit, which was introduced in ver 4.0.0, viewWillDisappear is being called in unexpected situations.

Here is how to reproduce it:

  1. Place PagingViewController and a UILabel in ViewController using a UIStackView.
  2. Transition from FirstViewController in PagingViewController to SecondViewController using pushViewController.
  3. Go back and change the layout in ViewController (e.g., hiding the UILabel).

At this point, didLayoutSubviews is initialized in PagingViewController.viewDidDisappear, but since viewDidLayoutSubviews is not called during the screen transition, didLayoutSubviews remains in the initialized state. This causes viewWillDisappear to be called unexpectedly when layout changes occur.

Transitioning from the ViewController in PagingViewController and returning to it is a common pattern in many use cases, and it is essential to address this issue because screen layout changes are often assumed in such cases.

Please find the code snippet below that reproduces the issue:

import UIKit
import Parchment

class ViewController: UIViewController, FirstViewControllerDelegate {
    private let label: UILabel = {
        let label = UILabel()
        label.text = "Layout Changed!"
        label.textAlignment = .center
        label.isHidden = true
        return label
    }()
    
    private let stackView: UIStackView = {
        let stackView = UIStackView()
        stackView.axis = .vertical
        stackView.distribution = .fill
        stackView.alignment = .fill
        stackView.spacing = 10
        return stackView
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let firstViewController = FirstViewController()
        firstViewController.delegate = self
        
        let pagingViewController = PagingViewController(viewControllers: [
            firstViewController
        ])

        addChild(pagingViewController)
        stackView.addArrangedSubview(pagingViewController.view)
        pagingViewController.didMove(toParent: self)

        pagingViewController.view.translatesAutoresizingMaskIntoConstraints = false

        stackView.addArrangedSubview(label)

        view.addSubview(stackView)
        stackView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            stackView.topAnchor.constraint(equalTo: view.topAnchor)
        ])
    }

    func didTapChangeLayoutButton() {
        label.isHidden.toggle()
        view.setNeedsLayout()
    }
}

protocol FirstViewControllerDelegate: AnyObject {
    func didTapChangeLayoutButton()
}

class FirstViewController: UIViewController {
    
    weak var delegate: FirstViewControllerDelegate?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        setupUI()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        print("FirstViewController.viewWillDisappear")
    }
    
    func setupUI() {
        let firstButton = UIButton(type: .system)
        firstButton.setTitle("Navigate", for: .normal)
        firstButton.addTarget(self, action: #selector(navigateToSecondVC), for: .touchUpInside)
        firstButton.frame = CGRect(x: 50, y: 100, width: 100, height: 50)
        view.addSubview(firstButton)
        
        let secondButton = UIButton(type: .system)
        secondButton.setTitle("Change Layout", for: .normal)
        secondButton.addTarget(self, action: #selector(changeLayout), for: .touchUpInside)
        secondButton.frame = CGRect(x: 50, y: 200, width: 150, height: 50)
        view.addSubview(secondButton)
    }
    
    @objc func navigateToSecondVC() {
        let secondVC = SecondViewController()
        navigationController?.pushViewController(secondVC, animated: true)
    }
    
    @objc func changeLayout() {
        delegate?.didTapChangeLayoutButton()
    }
}

class SecondViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .blue
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions