Edited at

iOS Avoid duplicate view controllers with custom NavigationController

It is possible that duplicate view controllers may be accidently instantiated by the user. This is particularly a risk if the segue to a new view controller follows the response and processing of a REST request.

If the view controllers are managed by a UINavigationController, we can modify its behaviour to avoid duplicate view controllers. This method assumes that only one instance of each View Controller class is allowed at one time.

First, we provide a identifier for each Object (and therefore View Controller) based on its class.

extension NSObject {

var className: String {
get {
return NSStringFromClass(type(of: self))
}
}
}

Then we subclass UINavigationController and override pushViewController; this method will now permit a new view controller to be added to the stack if

1. a view controller of this type does not already exist, and

2. another view controller is not already being added

class CustomNavigationController: UINavigationController {

var isNewViewControllerBeingAdded: Bool = false

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

func contains(viewController: UIViewController) -> Bool {
return self.viewControllers.map{ $0.className }.contains(viewController.className)
}

override func pushViewController(_ viewController: UIViewController, animated: Bool) {
if(!self.isNewViewControllerBeingAdded && !self.contains(viewController: viewController)) {
self.isNewViewControllerBeingAdded = true
super.pushViewController(viewController, animated: animated)
}
}
}

We also extend this subclass with a delegate handler, which modifies the "isNewViewControllerBeingAdded" flag upon successful addition of a view controller.

extension CustomNavigationController: UINavigationControllerDelegate {

func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
self.isNewViewControllerBeingAdded = false
}
}