gpt4 book ai didi

ios - UINavigationControllerDelegate 方法被调用两次

转载 作者:行者123 更新时间:2023-12-03 20:04:13 25 4
gpt4 key购买 nike

我已经建立了一个非常简单的项目,没有 Storyboard,一个窗口和一个 UINavigationController,其中包含一个普通的旧 UIViewController 作为 rootViewController。在 AppDelegate 中,我将 UINavigationController 的委托(delegate)设置为 self 并实现

navigationController:didShowViewController:animated 其中包含 1 行:

NSLog("didShow viewController")

当我启动我的应用程序时,UINavigationControllerDelegate 方法 navigationController:didShowViewController:animated 被调用两次。

应用程序委托(delegate):

import UIKit@UIApplicationMainclass 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    }}

第一个 View Controller :

import UIKitclass FirstViewController: UIViewController {    override func viewDidLoad() {        super.viewDidLoad()        self.view.backgroundColor = UIColor.blue        // Do any additional setup after loading the view, typically from a nib.    }    override func didReceiveMemoryWarning() {        super.didReceiveMemoryWarning()        // Dispose of any resources that can be recreated.    }}

我在更复杂的环境中尝试过这个 - 一个带有 UITabBarController 和 2 个 UINavigationController 作为 UITabBarController 的 viewController 的应用程序。奇怪的是,UINavigationControllerDelegate 方法在第一次显示 UINavigationController 时会触发两次,但此后只会触发一次。

有人知道如何纠正这个问题吗?根据文档,我认为正确的行为是 navigationController:didShowViewController:animated 在此示例应用程序中仅应调用一次。我还检查了点,确保委托(delegate)方法中的 navigationControllerviewController 参数是同一对象。

提前致谢!

编辑:这是每个调用的调用堆栈。全部在 UIKit 代码中,不是我的!

第一次通话:

29 elements  - 0 : "0   ???                                 0x0000000115145377 0x0 + 4648620919"  - 1 : "1   ???                                 0x0000000115145462 0x0 + 4648621154"  - 2 : "2   Test                                0x0000000105f22d00 main + 0"  - 3 : "3   Test                                0x0000000105f21e11 _TToFC4Test11AppDelegate20navigationControllerfTCSo22UINavigationController7didShowCSo16UIViewController8animatedSb_T_ + 97"  - 4 : "4   UIKit                               0x0000000106bab7a8 -[UINavigationController navigationTransitionView:didEndTransition:fromView:toView:] + 1660"  - 5 : "5   UIKit                               0x0000000106e8839e -[UINavigationTransitionView _notifyDelegateTransitionDidStopWithContext:] + 421"  - 6 : "6   UIKit                               0x0000000106e88677 -[UINavigationTransitionView _cleanupTransition] + 629"  - 7 : "7   UIKit                               0x0000000106a58f07 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 222"  - 8 : "8   UIKit                               0x0000000106a54bcb +[UIViewAnimationState popAnimationState] + 305"  - 9 : "9   UIKit                               0x0000000106e8810b -[UINavigationTransitionView transition:fromView:toView:] + 2582"  - 10 : "10  UIKit                               0x0000000106bb01d1 -[UINavigationController _startTransition:fromViewController:toViewController:] + 3301"  - 11 : "11  UIKit                               0x0000000106bb06b3 -[UINavigationController _startDeferredTransitionIfNeeded:] + 843"  - 12 : "12  UIKit                               0x0000000106bb17f1 -[UINavigationController __viewWillLayoutSubviews] + 58"  - 13 : "13  UIKit                               0x0000000106da32bc -[UILayoutContainerView layoutSubviews] + 231"  - 14 : "14  UIKit                               0x0000000106a9020b -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1268"  - 15 : "15  QuartzCore                          0x000000010bfbf904 -[CALayer layoutSublayers] + 146"  - 16 : "16  QuartzCore                          0x000000010bfb3526 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 370"  - 17 : "17  QuartzCore                          0x000000010bfb33a0 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24"  - 18 : "18  QuartzCore                          0x000000010bf42e92 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 294"  - 19 : "19  QuartzCore                          0x000000010bf6f130 _ZN2CA11Transaction6commitEv + 468"  - 20 : "20  QuartzCore                          0x000000010bf6fb37 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 115"  - 21 : "21  CoreFoundation                      0x000000010910f717 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23"  - 22 : "22  CoreFoundation                      0x000000010910f687 __CFRunLoopDoObservers + 391"  - 23 : "23  CoreFoundation                      0x00000001090f4038 CFRunLoopRunSpecific + 440"  - 24 : "24  UIKit                               0x00000001069c702f -[UIApplication _run] + 468"  - 25 : "25  UIKit                               0x00000001069cd0d4 UIApplicationMain + 159"  - 26 : "26  Test                                0x0000000105f22d37 main + 55"  - 27 : "27  libdyld.dylib                       0x000000010a19a65d start + 1"  - 28 : "28  ???                                 0x0000000000000001 0x0 + 1"  

第二次通话:

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"

最佳答案

经过实验,我发现iOS 13让UITabBarController中第一个UINavigationController的这个问题变得更加复杂。

第一个 UINavigationController 不会被调用堆栈[UINavigationController viewDidAppear:]

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 以下使用旧的解决方法,则第一次显示第一个 VC 并且仅第一个 VC 的 didShow 将不会被调用。

我能想到的新解决方法仍然是在 viewDidLoad 中设置委托(delegate),但尝试停止除了 TabBarVC 中的第一个之外的 VC 的第一次调用。

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:]`

所以创建一个标志,让除了第一个 UINavigationControllers 之外的 didShow 只在第一次时不被调用。

这里是解决这个问题的演示项目Demo

<小时/>

低于 iOS 13如果您只需要

func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, 动画: 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
}

}

但是有一个问题

func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, 动画: Bool)

由于您设置委托(delegate)太晚,第一次不会被调用,但第二次相同的 ViewController 实例 willShow 方法会正常调用。

附:如果你想在 UINavigationController 中实现 didShow 方法,你必须像这样设置委托(delegate):

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.viewDidAppear(animated)

中被调用

关于ios - UINavigationControllerDelegate 方法被调用两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44006847/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com