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


当前回答

你可以子类化UINavigationController并重写popViewController(animated: Bool)。除了能够在那里执行一些代码,你还可以防止用户完全返回,例如提示保存或丢弃他当前的工作。

示例实现,其中您可以设置popHandler,由推送的控制器设置/清除。

class NavigationController: UINavigationController
{
    var popHandler: (() -> Bool)?

    override func popViewController(animated: Bool) -> UIViewController?
    {
        guard self.popHandler?() != false else
        {
            return nil
        }
        self.popHandler = nil
        return super.popViewController(animated: animated)
    }
}

以及来自跟踪未保存工作的推送控制器的示例使用情况。

let hasUnsavedWork: Bool = // ...
(self.navigationController as! NavigationController).popHandler = hasUnsavedWork ?
    {
        // Prompt saving work here with an alert

        return false // Prevent pop until as user choses to save or discard

    } : nil // No unsaved work, we clear popHandler to let it pop normally

作为一个很好的触摸,这也将被interactivePopGestureRecognizer调用,当用户试图返回使用滑动手势。

其他回答

当返回按钮按下,忽略交互式弹出与屏幕边缘手势。

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    
    if isMovingFromParent, transitionCoordinator?.isInteractive == false {
      // code here
    }
  }

一种选择是实现您自己的自定义后退按钮。你需要添加以下代码到你的viewDidLoad方法:

    - (void) viewDidLoad {
        [super viewDidLoad];
        self.navigationItem.hidesBackButton = YES;
        UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStyleBordered target:self action:@selector(back:)];
        self.navigationItem.leftBarButtonItem = newBackButton;
    }

    - (void) back:(UIBarButtonItem *)sender {
        // Perform your custom actions
        // ...
        // Go back to the previous ViewController
        [self.navigationController popViewControllerAnimated:YES];
    }

更新:

以下是Swift的版本:

        override func viewDidLoad {
            super.viewDidLoad()
            self.navigationItem.hidesBackButton = true
            let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Bordered, target: self, action: "back:")
            self.navigationItem.leftBarButtonItem = newBackButton
        }

       @objc func back(sender: UIBarButtonItem) {
            // Perform your custom actions
            // ...
            // Go back to the previous ViewController
            self.navigationController?.popViewControllerAnimated(true)
        }

更新2:

以下是Swift 3的版本:

        override func viewDidLoad {
            super.viewDidLoad()
            self.navigationItem.hidesBackButton = true
            let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.plain, target: self, action: #selector(YourViewController.back(sender:)))
            self.navigationItem.leftBarButtonItem = newBackButton
        }

       @objc func back(sender: UIBarButtonItem) {
            // Perform your custom actions
            // ...
            // Go back to the previous ViewController
            _ = navigationController?.popViewController(animated: true)
        }

将按钮替换为另一个答案中建议的自定义按钮可能不是一个好主意,因为您将失去默认的行为和样式。

另一个选择是在视图控制器上实现viewWillDisappear方法,并检查名为isMovingFromParentViewController的属性。如果那个属性为真,它意味着视图控制器正在消失,因为它正在被移除(弹出)。

应该是这样的:

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

    if self.isMovingFromParentViewController {
        // Your code...
    }
}

在swift 4.2中

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

    if self.isMovingFromParent {
        // Your code...
    }
}

我通过以下方法做到了这一点:

斯威夫特3

override func didMoveToParentViewController(parent: UIViewController?) {
   super.didMoveToParentViewController(parent)

   if parent == nil {
      println("Back Button pressed.")
      delegate?.goingBack()
   }           
}

斯威夫特4

override func didMove(toParent parent: UIViewController?) {
    super.didMove(toParent: parent)

    if parent == nil {
        debugPrint("Back Button pressed.")
    }
}

不需要自定义后退按钮。

斯威夫特3:

override func didMove(toParentViewController parent: UIViewController?) {
    super.didMove(toParentViewController: parent)

    if parent == nil{
        print("Back button was clicked")
    }
}