UPDATED
Things are trickier if you want to know when the navigation bar pops an item, you need navigationBar:shouldPopItem:
. Check this out for more information. If you want to do something before the pop
, the best way I can think of is to extend the UINavigationController
.
@objc public protocol NavigationBarDelegate {
@objc optional func navigationBarShouldPop() -> Bool }
extension UINavigationController: UINavigationBarDelegate {
public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
if viewControllers.count < (navigationBar.items?.count)! {
// When it's being called twice
return true
}
guard let vc = self.topViewController else { return true }
var shouldPop = true
if vc.responds(to: #selector(vc.navigationBarShouldPop)) {
shouldPop = vc.navigationBarShouldPop()
}
if shouldPop {
DispatchQueue.main.async {
self.popViewController(animated: true)
}
} else {
DispatchQueue.main.async {
// To fix the problem of back button disabled
let dimmed = navigationBar.subviews.flatMap {$0.alpha < 1 ? $0 : nil}
UIView.animate(withDuration: 0.25, animations: {
dimmed.forEach { $0.alpha = 1 }
})
}
}
return false
}
}
And then if you want to do anything before your view controller get popped
class VC3: UIViewController, NavigationBarDelegate {
func navigationBarShouldPop() -> Bool {
// Do whatever you want here
return true
}
}
ORIGINAL
Assuming that you are in vc3
and of course you use NavigationController
now. There should be 3 scenarios:
(1) You want to go back to vc2
dismiss(animated: true, completion: nil)
(2) You want to navigate to a new view controller (vc4
) and you use interface builder
let vc4 = VC4(nibName: "VC4View", bundle: nil)
navigationController?.pushViewController(vc4, animated: true)
(3) You want to pop to a view on stack but not the immediately previous one. E.g., vc1
// If the destination view controller is already on the stack, just pop to it
for item in (navigationController?.viewControllers)! {
if item.isKind(of: VC1.self) {
_ = navigationController?.popToViewController(item, animated: true)
}
}