Ios UINavigationControllerDelegate方法调用两次
我已经建立了一个非常简单的项目,没有故事板,一个窗口和一个UINavigationController,其中包含一个普通的老UIViewController作为rootViewController。在AppDelegate中,我已将UINavigationController的委托设置为self并实现Ios UINavigationControllerDelegate方法调用两次,ios,iphone,swift,uiviewcontroller,uinavigationcontroller,Ios,Iphone,Swift,Uiviewcontroller,Uinavigationcontroller,我已经建立了一个非常简单的项目,没有故事板,一个窗口和一个UINavigationController,其中包含一个普通的老UIViewController作为rootViewController。在AppDelegate中,我已将UINavigationController的委托设置为self并实现 navigationController:didShowViewController:animated包含一行: NSLog(“显示视图控制器”) 当我启动我的应用程序时,UINavigation
navigationController:didShowViewController:animated
包含一行:
NSLog(“显示视图控制器”)
当我启动我的应用程序时,UINavigationControllerDelegate方法navigationController:didShowViewController:animated
会被调用两次
AppDelegate:
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UINavigationControllerDelegate {
var window: UIWindow?
var vc1: FirstViewController?
var nav1: UINavigationController?
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
NSLog("didShow viewController")
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
vc1 = FirstViewController()
nav1 = UINavigationController(rootViewController: vc1!)
nav1?.delegate = self
window = UIWindow(frame: UIScreen.main.bounds)
if let window = window {
window.backgroundColor = UIColor.white
window.rootViewController = nav1
window.makeKeyAndVisible()
}
return true
}
}
第二次电话:
20 elements
- 0 : "0 ??? 0x00000001151456e7 0x0 + 4648621799"
- 1 : "1 ??? 0x00000001151457d2 0x0 + 4648622034"
- 2 : "2 Test 0x0000000105f22d00 main + 0"
- 3 : "3 Test 0x0000000105f21e11 _TToFC4Test11AppDelegate20navigationControllerfTCSo22UINavigationController7didShowCSo16UIViewController8animatedSb_T_ + 97"
- 4 : "4 UIKit 0x0000000106ba949b -[UINavigationController viewDidAppear:] + 421"
- 5 : "5 UIKit 0x0000000106b7595e -[UIViewController _setViewAppearState:isAnimating:] + 704"
- 6 : "6 UIKit 0x0000000106b7863b __64-[UIViewController viewDidMoveToWindow:shouldAppearOrDisappear:]_block_invoke + 42"
- 7 : "7 UIKit 0x0000000106b76a7b -[UIViewController _executeAfterAppearanceBlock] + 86"
- 8 : "8 UIKit 0x00000001069d992f _runAfterCACommitDeferredBlocks + 634"
- 9 : "9 UIKit 0x00000001069c67bc _cleanUpAfterCAFlushAndRunDeferredBlocks + 532"
- 10 : "10 UIKit 0x00000001069e957d __84-[UIApplication _handleApplicationActivationWithScene:transitionContext:completion:]_block_invoke_2 + 155"
- 11 : "11 CoreFoundation 0x000000010910fb5c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12"
- 12 : "12 CoreFoundation 0x00000001090f4e54 __CFRunLoopDoBlocks + 356"
- 13 : "13 CoreFoundation 0x00000001090f45ee __CFRunLoopRun + 894"
- 14 : "14 CoreFoundation 0x00000001090f4016 CFRunLoopRunSpecific + 406"
- 15 : "15 GraphicsServices 0x000000010b100a24 GSEventRunModal + 62"
- 16 : "16 UIKit 0x00000001069cd0d4 UIApplicationMain + 159"
- 17 : "17 Test 0x0000000105f22d37 main + 55"
- 18 : "18 libdyld.dylib 0x000000010a19a65d start + 1"
- 19 : "19 ??? 0x0000000000000001 0x0 + 1"
20个要素
-0:“0???0x00000001151456e7 0x0+4648621799”
-1:“1???0x00000001151457d2 0x0+4648622034”
-2:“2测试0x0000000105f22d00主+0”
-3:“3测试0x0000000105f21e11测试应用程序授权20导航控制器TCSO22 UINAVIGATIONCONTROLLER7DIDshowCSO16UIViewController8animatedSB\uU97”
-4:“4 UIKit 0x0000000106ba949b-[UINavigationController视图显示:][421”
-5:“5 UIKit 0x0000000106b7595e-[UIViewController\u setViewAppearState:isAnimating:+704”
-6:“6 UIKit 0x0000000106b7863b u 64-[UIViewController ViewDidMoveToWindows:shouldApparOrdAppear:][u块invoke+42”
-7:“7 UIKit 0x0000000106b76a7b-[UIViewController\U ExecuteAAfterAppearanceBlock]+86”
-8:“8 UIKit 0x00000001069d992f\u运行在CACommitDeferredBlocks+634之后”
-9:“9 UIKit 0x00000001069c67bc在CAFLUSHANDRUNDERDERREDBLOCKS+532”后进行清洁
-10:“10 UIKit 0x00000001069e957d \uuu84-[UIApplication\uHandLeapplicationActivationwithscene:transitionContext:completion:][uBlock\uInvoke\u2+155”
-11:“11 CoreFoundation 0x000000010910fb5c\uuuu CFRUNLOOP\u正在调用\u OUT\u到\u块\uuuuu+12”
-12:“12 CoreFoundation 0x00000001090f4e54\uu CFRunLoopDoBlocks+356”
-13:“13 CoreFoundation 0x00000001090f45ee__CFRunLoopRun+894”
-14:“14 CoreFoundation 0x00000001090f4016 CFRunLoopRunSpecific+406”
-15:“15个图形服务0x000000010b100a24 GSEventRunModal+62”
-16:“16 UIKit 0x00000001069cd0d4 UIApplicationMain+159”
-17:“17测试0x0000000105f22d37主+55”
-18:“18 libdyld.dylib 0x000000010a19a65d启动+1”
-19:“19???0x0000000000000001 0x0+1”
经过实验,我发现iOS 13使UITabBarController中第一个UINavigationController的问题变得更加复杂 不会为调用堆栈调用第一个UINavigationController
[UINavigationController ViewDidDisplay://代码>
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.delegate = self
}
}
extension ViewController: UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
print("willShow")
}
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
print("didShow")
}
}
输出将是
willShow
didShow -> this one is from call stack `[UINavigationController __viewWillLayoutSubviews]`
对于第一个选项卡
这意味着,如果您使用的是iOS 13下面的旧解决方案,那么第一次显示first VC时,将不会调用first VC的didShow
我能想到的新解决方法仍然是在viewDidLoad
中设置委托,但尝试停止对VC的第一次调用,而不是在TabBarVC中的第一次调用
将按此顺序调用didShow
LAUNCH APP
VC1 willShow
VC1 didShow `[UINavigationController __viewWillLayoutSubviews]`
SELECT SECOND TAB
VC2 willShow
VC2 didShow `[UINavigationController __viewWillLayoutSubviews]`
VC2 didShow `[UINavigationController viewDidAppear:]` -> this is the one I try to get rid off
SELECT BACK TO FIRST TAB
VC1 willShow
VC1 didShow `[UINavigationController viewDidAppear:]`
SELECT BACK TO SECOND TAB
VC2 willShow
VC2 didShow `[UINavigationController viewDidAppear:]`
因此,设置一个标志,以使第一次调用UINavigationController'didShow
之外的控件不会被第一次调用
下面是解决这个问题的演示项目
低于iOS 13 如果你只需要
func-navigationController(\unavigationcontroller:UINavigationController,didShow-viewController:UIViewController,animated:Bool)
然后有一个工作环境可以这样设置:
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationController?.delegate = self
}
}
extension ViewController: UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
// do something
}
}
class NavigationController: UINavigationController {
override func viewDidAppear(_ animated: Bool) {
delegate = self
super.viewDidAppear(animated)
}
}
extension NavigationController: UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
print("will")
}
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
print("did")
}
}
但有一个问题
func-navigationController(\unavigationcontroller:UINavigationController,willShow-viewController:UIViewController,animated:Bool)
第一次将不会被调用,因为您设置委托太晚,但第二次相同的ViewController
instance将正常调用show
方法
p、 如果要在UINavigationController中实现didShow
方法,必须如下设置委托:
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationController?.delegate = self
}
}
extension ViewController: UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
// do something
}
}
class NavigationController: UINavigationController {
override func viewDidAppear(_ animated: Bool) {
delegate = self
super.viewDidAppear(animated)
}
}
extension NavigationController: UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
print("will")
}
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
print("did")
}
}
由于
didShow
方法在super.viewdidsearch(动画)
中被调用,请尝试在导航委托方法中添加断点,并查看调用方法的堆栈跟踪。我已为每个调用添加了上面的调用堆栈。谢谢你看!查看此博客并放置断点,查看指向视图控制器的指针是否相同。我很好奇到底是两个独立的视图控制器被显示,还是只有一个。也许当你设置根视图控制器时,它会被调用一次,当你在窗口上设置导航控制器时,它会被调用一次?