Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/101.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/39.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios UINavigationControllerDelegate方法调用两次_Ios_Iphone_Swift_Uiviewcontroller_Uinavigationcontroller - Fatal编程技术网

Ios UINavigationControllerDelegate方法调用两次

Ios UINavigationControllerDelegate方法调用两次,ios,iphone,swift,uiviewcontroller,uinavigationcontroller,Ios,Iphone,Swift,Uiviewcontroller,Uinavigationcontroller,我已经建立了一个非常简单的项目,没有故事板,一个窗口和一个UINavigationController,其中包含一个普通的老UIViewController作为rootViewController。在AppDelegate中,我已将UINavigationController的委托设置为self并实现 navigationController:didShowViewController:animated包含一行: NSLog(“显示视图控制器”) 当我启动我的应用程序时,UINavigation

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

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(动画)

中被调用,请尝试在导航委托方法中添加断点,并查看调用方法的堆栈跟踪。我已为每个调用添加了上面的调用堆栈。谢谢你看!查看此博客并放置断点,查看指向视图控制器的指针是否相同。我很好奇到底是两个独立的视图控制器被显示,还是只有一个。也许当你设置根视图控制器时,它会被调用一次,当你在窗口上设置导航控制器时,它会被调用一次?