在容器视图中关闭模态和 return 以呈现子 ViewController

dimiss modal and return to presented childViewController in containerView

我在关闭从容器视图中的 childviewController 呈现的模态视图时遇到了一些问题。我有一个 UINavigationController 作为 rootViewController (MainNavigationController),并呈现来自 selectedSegmentIndex 1 (secondViewController) 的 childViewController 之一的模式。模态呈现良好,但是当我关闭模态以返回到 secondViewController(HomeController 的子类)时,它 return 使我回到 selectedIndex 0,而不是从中呈现的 selectedIndex 1 childViewController。我希望模式消失,return 用户回到 childViewController,它是从(secondViewController)呈现的,而不是 return 回到 selectedIndex 0。提前致谢!

// NavigationConroller 作为 rootViewController

class MainNavigationController: UINavigationController {

    var segmentedController: UISegmentedControl!

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        let vc1 = TravelersFeedVC()
        let vc2 = ProfileVC()

        if isLoggedIn() {
            // assume user is logged in
            let homeController = HomeController()
            viewControllers = [homeController]
            homeController.firstViewController = vc1
            homeController.secondViewController = vc2

        } else {
            perform(#selector(showLoginController), with: nil, afterDelay: 0.01)
        }
    }

    fileprivate func isLoggedIn() ->  Bool {
        return UserDefaults.standard.isLoggedIn()
    }

    func showLoginController() {
        let loginController = LoginController()
        present(loginController, animated: true, completion: {
            // perhaps do something here later
        })
    }
}

// HomeController 作为 parentViewController

class HomeController: UIViewController, FBSDKLoginButtonDelegate {

    // child view controllers to put inside content view
    var firstViewController: TravelersFeedVC?
    var secondViewController: ProfileVC?

    private var activeViewController: UIViewController? {
        didSet {
            removeInactiveViewController(inactiveViewController: oldValue)
            updateActiveViewController()
        }
    }

    private func removeInactiveViewController(inactiveViewController: UIViewController?) {
        if let inActiveVC = inactiveViewController {
            // call before removing child view controller's view from hierarchy
            inActiveVC.willMove(toParentViewController: nil)

            inActiveVC.view.removeFromSuperview()

            // call after removing child view controller's view from hierarchy
            inActiveVC.removeFromParentViewController()
        }
    }

    private func updateActiveViewController() {
        if let activeVC = activeViewController {
            // call before adding child view controller's view as subview
            addChildViewController(activeVC)

            activeVC.view.frame = contentView.bounds
            contentView.addSubview(activeVC.view)

            // call before adding child view controller's view as subview
            activeVC.didMove(toParentViewController: self)
        }
    }

    // UI elements
    lazy var contentView: UIView = {
        let tv = UIView()
        tv.backgroundColor = UIColor.purple
        tv.translatesAutoresizingMaskIntoConstraints = false
        tv.layer.masksToBounds = true
        return tv
    }()


    var segmentedController: UISegmentedControl!

    override func viewDidLoad() {
        super.viewDidLoad()

        activeViewController = firstViewController

        checkIfUserIsLoggedIn()

        view.addSubview(contentView)

        setupProfileScreen()

        let items = ["Travelers", "Me"]
        segmentedController = UISegmentedControl(items: items)
        navigationItem.titleView = segmentedController

        segmentedController.tintColor = UIColor.black
        segmentedController.selectedSegmentIndex = 0

        // Add function to handle Value Changed events
        segmentedController.addTarget(self, action: #selector(HomeController.segmentedValueChanged(_:)), for: .valueChanged)

        navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Sign Out", style: .plain, target: self, action: #selector(handleSignOut))
        navigationItem.leftBarButtonItem?.tintColor = UIColor.black

    }


    // reference to collectionViewController
    var travelersFeedVC: TravelersFeedVC!

    func segmentedValueChanged(_ sender:UISegmentedControl!)
    {
        switch segmentedController.selectedSegmentIndex {
        case 0:
            activeViewController = firstViewController

        case 1:
            activeViewController = secondViewController

        default: // Do nothing
            break
        }
    }

// containerView 中的 secondViewcontroller,其中模态来自

class ProfileVC: UIViewController {

// button to present modal
    lazy var placesButton: UIButton = {
        let customButton = UIButton(type: .system)
        customButton.backgroundColor = UIColor.clear
//        customButton.frame = CGRect(x: 150, y: 50, width: 120, height: self.view.frame.height)
        customButton.setTitle("## of Places", for: .normal)
        customButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
        customButton.setTitleColor(.white, for: .normal)
        customButton.addTarget(self, action: #selector(handleShowPlacesVC), for: .touchUpInside)

        return customButton
    }()

// function to call to present modal
    func handleShowPlacesVC() {
        let placesVC = PlacesTableVC()
        let navigationController = UINavigationController(rootViewController: placesVC)
        present(navigationController, animated: true, completion: nil)
    }

// 要关闭的模态视图

   override func viewDidLoad() {
        super.viewDidLoad()

        navigationItem.leftBarButtonItem = UIBarButtonItem(title: "back", style: .plain, target: self, action: #selector(handleCancel))

    }

// dismiss modal view to return to secondViewController in childViewController containerView
    func handleCancel() {
        dismiss(animated: true, completion: nil)
    }

关闭模态对话框时,将调用 MainNavigationController 中的 viewDidAppear 函数。在那里你设置了一个新的 homeController 和它的孩子。这将在设置为 firstViewController 的 HomeController 中触发 viewDidload。尝试在那里设置一个断点,你会看到它。

我建议避免在 viewDidAppear 中创建内容,改用 viewDidLoad。

另一个提示:'dismiss' 定义为:'Dismisses the view controller that was presented modally by the view controller.' - 如果您在模式 vc 上方打开一个警报,它会关闭警报,而不是模式视图(自我) .正确的实现必须在呈现控制器(打开它的同一控制器)上调用 dismiss:"presentingViewController?.dismiss()" 它在您的代码中有效,因为苹果已经为没有任何内容的情况实施了回退,但这是一个有时会引起一些头痛的陷阱。

很有可能,虽然您是从子视图控制器调用 present,但它实际上并没有处理演示文稿。来自 Apple docs:

The object on which you call this method may not always be the one that handles the presentation. Each presentation style has different rules governing its behavior. For example, a full-screen presentation must be made by a view controller that itself covers the entire screen. If the current view controller is unable to fulfill a request, it forwards the request up the view controller hierarchy to its nearest parent, which can then handle or forward the request.

由于您要保留对活动视图控制器的引用,一种解决方案可能是在关闭时显式设置索引。