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
- a view controller of this type does not already exist, and
- 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
}
}