我的应用程序从一个登录屏幕开始,该屏幕连接到 CreateRequestTableViewController
,并且所有内容都嵌入在导航控制器中,因此 CreateRequest
vc 的后退按钮返回到登录屏幕.我想在用户注销之前询问用户是否确定,并且 navcon 会弹出 vc 以再次显示登录屏幕.
My app starts with a login screen that segues to CreateRequestTableViewController
, and everything is embedded in a navigation controller, so the back button for the CreateRequest
vc goes back to the login screen. I want to ask the user if they're sure they before they're logged out and the navcon pops the vc to show the Login screen again.
我已经让它与下面的代码一起工作,除了在我重新登录并移回 CreateRequest
VC(创建一个新实例)后,我收到一个致命错误:
I've gotten it to work with the code below, except that after I log back in and move back to the CreateRequest
VC (creating a new instance) I get a fatal error:
'NSInternalInconsistencyException', reason: '无法在控制器管理的 UINavigationBar 上手动设置委托.'
这让我有点过头了.我尝试添加下面代码中包含的 deinit
方法,但没有成功.
This puts me in just a little bit over my head. I've tried adding the deinit
method that's included in the code below, with no luck.
特别奇怪的是,它在我分配委托时(或者当我将其设置为 nil 时)第一次没有崩溃,正如错误文本所暗示的那样.
It's especially strange that it doesn't crash the first time I assign the delegate (or when I set it to nil either), as the text of the error would suggest.
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.delegate = self
}
deinit {
navigationController?.navigationBar.delegate = nil
}
func confirmLogout() {
let alert = UIAlertController(title: "Log Out", message: "Are you sure you want to log out?", preferredStyle: .alert)
let yesButton = UIAlertAction(title: "Log out", style: .destructive) { (_) in
if let loginVC = self.navigationController?.viewControllers.first as? SignInTableViewController {
self.navigationController?.popViewController(animated: true)
loginVC.logOutAll()
}
}
let noButton = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alert.addAction(yesButton)
alert.addAction(noButton)
present(alert, animated: true, completion: nil)
}
func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
if navigationController?.viewControllers.last is CreateRequestTableViewController {
confirmLogout()
return false
}
navigationController?.popViewController(animated: true)
return true
}
我通过派生自定义导航控制器解决了这个问题,该控制器设置了自己的专用导航栏委托.
I've solved this problem by deriving custom navigation controller that sets up it's own specialised navigation bar delegate.
此委托(转发者):
自定义导航控制器添加了一个新的navigationBarDelegate"属性,您可以使用它来设置您的委托.你应该在 viewDidAppear:animated: 和 viewWillDisappear:animated: 方法中这样做.
The custom navigation controller adds a new "navigationBarDelegate" property that you can use to setup your delegate. You should do that in viewDidAppear:animated: and viewWillDisappear:animated: methods.
这里是代码(Swift 4):
Here is the code (Swift 4):
class NavigationController : UINavigationController
{
fileprivate var originaBarDelegate:UINavigationBarDelegate?
private var forwarder:Forwarder? = nil
var navigationBarDelegate:UINavigationBarDelegate?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
if navigationBar.delegate != nil {
forwarder = Forwarder(self)
}
}
}
fileprivate class Forwarder : NSObject, UINavigationBarDelegate {
weak var controller:NavigationController?
init(_ controller: NavigationController) {
self.controller = controller
super.init()
controller.originaBarDelegate = controller.navigationBar.delegate
controller.navigationBar.delegate = self
}
let shouldPopSel = #selector(UINavigationBarDelegate.navigationBar(_:shouldPop:))
let didPopSel = #selector(UINavigationBarDelegate.navigationBar(_:didPop:))
let shouldPushSel = #selector(UINavigationBarDelegate.navigationBar(_:shouldPush:))
let didPushSel = #selector(UINavigationBarDelegate.navigationBar(_:didPush:))
func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
if let delegate = controller?.navigationBarDelegate, delegate.responds(to: shouldPopSel) {
if !delegate.navigationBar!(navigationBar, shouldPop: item) {
return false
}
}
if let delegate = controller?.originaBarDelegate, delegate.responds(to: shouldPopSel) {
return delegate.navigationBar!(navigationBar, shouldPop: item)
}
return true
}
func navigationBar(_ navigationBar: UINavigationBar, didPop item: UINavigationItem) {
if let delegate = controller?.navigationBarDelegate, delegate.responds(to: didPopSel) {
delegate.navigationBar!(navigationBar, didPop: item)
}
if let delegate = controller?.originaBarDelegate, delegate.responds(to: didPopSel) {
return delegate.navigationBar!(navigationBar, didPop: item)
}
}
func navigationBar(_ navigationBar: UINavigationBar, shouldPush item: UINavigationItem) -> Bool {
if let delegate = controller?.navigationBarDelegate, delegate.responds(to: shouldPushSel) {
if !delegate.navigationBar!(navigationBar, shouldPush: item) {
return false
}
}
if let delegate = controller?.originaBarDelegate, delegate.responds(to: shouldPushSel) {
return delegate.navigationBar!(navigationBar, shouldPush: item)
}
return true
}
func navigationBar(_ navigationBar: UINavigationBar, didPush item: UINavigationItem) {
if let delegate = controller?.navigationBarDelegate, delegate.responds(to: didPushSel) {
delegate.navigationBar!(navigationBar, didPush: item)
}
if let delegate = controller?.originaBarDelegate, delegate.responds(to: didPushSel) {
return delegate.navigationBar!(navigationBar, didPush: item)
}
}
}
用法如下:
将以下代码放入视图控制器
Put the following code into your view controller
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
(navigationController as? NavigationController)?.navigationBarDelegate = self
}
override func viewWillDisappear(_ animated: Bool) {
(navigationController as? NavigationController)?.navigationBarDelegate = nil
super.viewWillDisappear(animated)
}
在您的视图控制器中实现一个或多个 UINavigationBarDelegate 方法(这只是一个示例):
implement one or more of UINavigationBarDelegate methods in your view controller (this is just an example):
func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
let alert = UIAlertController(title: "Do you really want to leave the page?", message: "All changes will be lost", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Stay here", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: "Leave", style: .destructive, handler: { action in
self.navigationController?.popViewController(animated: true)
}))
self.present(alert, animated: true)
return false
}
这篇关于例外:无法在控制器管理的 UINavigationBar 上手动设置委托的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!