Reputation: 51
I've upgraded the Xcode to 11, and I found some issues on iOS13 Simulators/real devices of our iOS app with shouldPop() method from UINavigationBarDelegate protocol:
This protocol has 4 methods, 3 of them are working fine, only this shouldPop() doesn't work anymore. If I run the app on previous iOS version devices/Simulators, everything is fine, shouldPop() is called but if I run the app on iOS13, shouldPop() is not called. Because on previous iOS version everything is ok, 3 out of 4 methods of the protocol are called and I din't find in documentation that shouldPop() is not-supported/deprecated, it seems to be a bug, but I am not sure.
Do you guys have any idea about this?
Thank you, Tibi.
private class DummyNavigationController: UINavigationController, UINavigationControllerDelegate, UINavigationBarDelegate {
var rootViewController: UIViewController? {
didSet {
self.delegate = self
}
}
func navigationBar(_ navigationBar: UINavigationBar, didPush item: UINavigationItem) {
// working
}
func navigationBar(_ navigationBar: UINavigationBar, shouldPush item: UINavigationItem) -> Bool {
// working
return true
}
func navigationBar(_ navigationBar: UINavigationBar, didPop item: UINavigationItem) {
// working
}
func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
// not working
return true
}
}
private class DummyViewController: UIViewController {
convenience init(_ showBackText: Bool) {
self.init()
if !showBackText {
self.navigationItem.title = ""
}
}
}
class OpenModalWithNavigation {
static func present(viewController: UIViewController,
parentViewController: UIViewController,
showBackText: Bool = false,
presentationStyle: UIModalPresentationStyle = .overCurrentContext,
transitionStyle: UIModalTransitionStyle = .crossDissolve) {
let navController = DummyNavigationController()
navController.rootViewController = parentViewController
navController.pushViewController(DummyViewController(showBackText), animated: false)
navController.pushViewController(viewController, animated: false)
navController.modalPresentationStyle = presentationStyle
navController.modalTransitionStyle = transitionStyle
parentViewController.present(navController, animated: true, completion: nil)
}
}
Edit: After some investigation in our big code, yes, we call popViewController() from a custom "back" button. It's somehow similar with the code below: if I put in DummyNavigationController via OpenModalWithNavigation.present() a qqq instance, the shouldPop() is not fired.
class qqq: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.green
let button = UIButton(type: .custom)
let backImage = UIImage(named: "back")
button.setImage(backImage, for: .normal)
button.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
button.addTarget(self, action: #selector(self.goBack), for: .touchUpInside)
let backButton = UIBarButtonItem(customView: button)
self.navigationItem.leftBarButtonItem = backButton
}
@objc func goBack() {
self.navigationController?.popViewController(animated: true)
}
}
Also, the simplified form of qqq (see below), it will not work... It seems to be related to popViewController()
class qqq: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2), execute: {
self.navigationController?.popViewController(animated: true)
})
}
}
If I press the default back button, everything is ok, shouldPop() is called; not when we call popViewController() - this is happening only on an iOS13 running device/simulator; for pre-iOS13: everything is fine.
Upvotes: 1
Views: 2392
Reputation: 101
I have experienced the same issue when using an extension on UINavigationController in the simulator.
I have therefore decided to use a concrete class as the delegate. Since I am not making very many of them, maximally three or four per storyboard. Setting the Custom class field in the storyboard doesn't seem too bad.
Upvotes: 0
Reputation: 1235
In iOS 13.4 it only works if implemented in the same file of the controller that uses it, could be in a separate extension but must be the same file... that is. The other three methods still continue to work as before, as they should.
At least this is how I solved the problem, I had the implementation in a generic extension inside a framework that stopped working.
Upvotes: 1
Reputation: 176
This isn't answer to your question but if it helps anyone...
shouldPop wasn't called for me in a simulator but it worked on a device. I had shouldPop method declared in an extension of UINavigationController. I removed it from extension and put it in UINavigationController subclass and now it works in simulator too.
Upvotes: 0
Reputation: 634
It seems that it's not working properly only on the iOS simulator. If you try to run on the device, everything is fine.
Upvotes: 1
Reputation: 301
Remove private access modifier from Navigation controller class declaration.
class DummyNavigationController: UINavigationController, UINavigationControllerDelegate, UINavigationBarDelegate {
var rootViewController: UIViewController? {
didSet {
self.delegate = self
}
}
func navigationBar(_ navigationBar: UINavigationBar, didPush item: UINavigationItem) {
// working
}
func navigationBar(_ navigationBar: UINavigationBar, shouldPush item: UINavigationItem) -> Bool {
// working
return true
}
func navigationBar(_ navigationBar: UINavigationBar, didPop item: UINavigationItem) {
// working
}
func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
// working
return true
}
}
Private access restricts the use of an entity/class to the enclosing declaration, and to extensions of that declaration that are in the same file.
If you still face issue let me know.
Upvotes: 0