我需要执行一个动作(清空一个数组),当UINavigationController的后退按钮被按下,而按钮仍然导致堆栈上的前一个ViewController出现。我如何使用swift来实现这一点?


当前回答

override func willMove(toParent parent: UIViewController?)
{
    super.willMove(toParent: parent)
    if parent == nil
    {
        print("This VC is 'will' be popped. i.e. the back button was pressed.")
    }
}

其他回答

这是我自己解决问题的方法

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationItem.leftBarButtonItem?.action = #selector(self.back(sender:))
    self.navigationItem.leftBarButtonItem?.target = self
}

@objc func back(sender: UIBarButtonItem) {

}

这里有一个最简单的Swift 5解决方案,它不需要你创建一个自定义的后退按钮,也不需要你放弃所有免费获得的UINavigationController左键功能。

正如Brandon A上面建议的那样,你需要在你想要与之交互的视图控制器中实现UINavigationControllerDelegate。一个好方法是创建一个unwind segue,你可以手动或自动地执行,并从自定义完成按钮或后退按钮重用相同的代码。

首先,让你感兴趣的视图控制器(你想检测返回的那个)在它的viewDidLoad中成为导航控制器的委托:

override func viewDidLoad() {
    super.viewDidLoad()
    navigationController?.delegate = self
}

其次,在文件底部添加一个扩展,覆盖navigationController(willShow:animated:)

extension PickerTableViewController: UINavigationControllerDelegate {

    func navigationController(_ navigationController: UINavigationController,
                              willShow viewController: UIViewController,
                              animated: Bool) {

        if let _ = viewController as? EditComicBookViewController {

            let selectedItemRow = itemList.firstIndex(of: selectedItemName)
            selectedItemIndex = IndexPath(row: selectedItemRow!, section: 0)

            if let selectedCell = tableView.cellForRow(at: selectedItemIndex) {
                performSegue(withIdentifier: "PickedItem", sender: selectedCell)
            }
        }
    }
}

因为你的问题包含了一个UITableViewController,所以我包含了一种获取用户点击行的索引路径的方法。

在我的例子中,viewWillDisappear效果最好。但在某些情况下,必须修改之前的视图控制器。所以这是我的解决方案访问之前的视图控制器,它在Swift 4中工作:

override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if isMovingFromParentViewController {
            if let viewControllers = self.navigationController?.viewControllers {
                if (viewControllers.count >= 1) {
                    let previousViewController = viewControllers[viewControllers.count-1] as! NameOfDestinationViewController
                    // whatever you want to do
                    previousViewController.callOrModifySomething()
                }
            }
        }
    }

这就是我的解

extension UINavigationController: UINavigationBarDelegate {
    public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
        if let shouldBlock = self.topViewController?.shouldPopFromNavigation() {
            return shouldBlock
        }
        return true
    }
}

extension UIViewController {
    @objc func shouldPopFromNavigation() -> Bool {
        return true
    }
}

在你的视图控制器中,你可以这样处理:

@objc override func shouldPopFromNavigation() -> Bool {
        // Your dialog, example UIAlertViewController or whatever you want
        return false
    }
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    if self.isMovingToParent {

        //your code backView
    }
}