Setting delegate to nil
as described in this answer causes some nasty bugs in iOS 11, for example this one
But the idea of stubbing the delegate is good in general. For example, you can write the following code
final class NavigationController: UINavigationController {
private var customDelegate: InteractivePopGestureRecognizerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
customDelegate = InteractivePopGestureRecognizerDelegate(
originalDelegate: interactivePopGestureRecognizer?.delegate,
navigationController: self
)
interactivePopGestureRecognizer?.delegate = customDelegate
}
}
Then you can use your custom delegate to fix the root cause of the problem
final class InteractivePopGestureRecognizerDelegate:
NSObject,
UIGestureRecognizerDelegate
{
private weak var originalDelegate: UIGestureRecognizerDelegate?
private weak var navigationController: UINavigationController?
init(
originalDelegate: UIGestureRecognizerDelegate?,
navigationController: UINavigationController)
{
self.originalDelegate = originalDelegate
self.navigationController = navigationController
}
func gestureRecognizer(
_ gestureRecognizer: UIGestureRecognizer,
shouldReceive touch: UITouch)
-> Bool
{
if let originalDelegate = originalDelegate,
let result = originalDelegate.gestureRecognizer?(
gestureRecognizer,
shouldReceive: touch)
{
if !result {
// Your interactive pop gesture got cancelled here
// Perform sanity check of pop possibility
if (navigationController?.viewControllers.count ?? 0) < 2 {
return result
}
if navigationController?.navigationBar.isHidden == true {
// Return true here if you want to swipe even without navigation bar
return result
}
// Enable pop gesture
return true
}
} else {
return true
}
}
...
// Proxy all other `UIGestureRecognizerDelegate` methods to the originalDelegate here
...
}
Of course this is a bit tricky and may not work in the future (like every other hack)