【问题标题】:Can UINavigationController only handle a maximum of 4 Viewcontrollers?UINavigationController 最多只能处理 4 个 Viewcontroller 吗?
【发布时间】:2016-07-15 02:07:20
【问题描述】:

我正在尝试在 Xcode 7.x 中构建一个故事板,其中在 UINavigationController 中嵌入了超过 4 个连续的视图控制器。 导航控制器是初始视图控制器。 Embedded 是一个简单的视图控制器,只包含一个按钮,它连接到一个 Adaptive Show Segue,调用一个类似的视图控制器等等。每个人都通过一个简单的 Show Segue 调用下一个。 Push 仅适用于 3 次连续调用,此后对导航控制器的引用丢失。 第 5 个视图控制器及以后的视图控制器以模态方式呈现。

至少从 iOS 8 开始,我在不同的项目中遇到了这个问题。

UINavigationController viewControllers 堆栈是否限制为 4 个条目?

More than 4 view controllers embedded in an UINavigationController

嵌入式视图控制器的代码:

class ViewController: UIViewController {

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)

        print("ViewCintroller:\(title) NavController:\(navigationController) stack size:\(navigationController?.viewControllers.count)")
        print()
    }
}

输出:

ViewController:Optional("V1") NavController:Optional(<UINavigationController: 0x7fd57b024200>) stack size:Optional(1)
ViewController:Optional("V2") NavController:Optional(<UINavigationController: 0x7fd57b024200>) stack size:Optional(2)
ViewController:Optional("V3") NavController:Optional(<UINavigationController: 0x7fd57b024200>) stack size:Optional(3)
ViewController:Optional("V4") NavController:Optional(<UINavigationController: 0x7fd57b024200>) stack size:Optional(4)
ViewController:Optional("V5") NavController:nil stack size:nil
ViewController:Optional("V6") NavController:nil stack size:nil

将所有 segues 更改为已弃用的推送类型会导致所需的结果:

ViewController:Optional("V1") NavController:Optional(<UINavigationController: 0x7fc8a1026200>) stack size:Optional(1)
ViewController:Optional("V2") NavController:Optional(<UINavigationController: 0x7fc8a1026200>) stack size:Optional(2)
ViewController:Optional("V3") NavController:Optional(<UINavigationController: 0x7fc8a1026200>) stack size:Optional(3)
ViewController:Optional("V4") NavController:Optional(<UINavigationController: 0x7fc8a1026200>) stack size:Optional(4)
ViewController:Optional("V5") NavController:Optional(<UINavigationController: 0x7fc8a1026200>) stack size:Optional(5)
ViewController:Optional("V6") NavController:Optional(<UINavigationController: 0x7fc8a1026200>) stack size:Optional(6)

编辑:

在我看来,问题出在界面构建器上。 我得到了一个可行的解决方案,将所有 show segues 更改为 push segues,编译,将 push segues 更改回 show segues,再次编译,异常消失了。导航堆栈不再局限于 4 个视图控制器。

【问题讨论】:

    标签: ios swift uinavigationcontroller


    【解决方案1】:

    每个人都通过一个简单的 Show Segue 调用下一个人。 Push 仅适用于 3 次连续调用,此后对导航控制器的引用丢失。 第 5 个视图控制器及以后的视图控制器以模态方式呈现。

    我在你的问题中添加了对这句话的强调。

    模态显示的视图控制器将为其navigationController 属性返回nil,因为它没有嵌入到导航控制器中。如果您继续使用 Show 序列而不是模态显示第 5、6 等等,您将继续看到导航控制器不是nil 并且导航堆栈将继续增加(直到设备用完内存)。

    除了可用的设备内存之外,可以添加到导航控制器导航堆栈的视图控制器的数量没有限制。

    以模态方式呈现视图控制器不会将其添加到导航控制器的导航堆栈中。模态呈现的视图控制器将为其navigationController 属性返回nil,因为它没有嵌入到导航堆栈中。


    考虑以下示例:

    我创建了这个NextViewController 类。视图控制器只有“添加另一个”按钮,它与showAnother 方法挂钩。此方法实例化另一个NextViewController 并将其压入堆栈。在viewWillAppear 中,我记录的内容与您在prepareForSegue 方法中记录的内容相同。

    我可以连续点击“添加另一个”任意多次,我会继续获取另一个视图控制器添加到导航堆栈中,您可以从日志消息中看到堆栈中的视图控制器数量正在增加很好超过四个。 (屏幕截图中的 27)。这很消耗内存,最终我会用完,是的。

    这是NextViewController 类的纯文本代码:

    import UIKit
    
    class NextViewController: UIViewController {
        init() {
            super.init(nibName: "NextViewController", bundle: NSBundle.mainBundle())
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        override func viewWillAppear(animated: Bool) {
            super.viewWillAppear(animated)
            print("ViewCintroller:\(title) NavController:\(navigationController) stack size:\(navigationController?.viewControllers.count)")
        }
    
        @IBAction func showAnother() {
            navigationController?.pushViewController(NextViewController(), animated: true)
        }
    }
    

    为了完整起见,我添加了第二个按钮,它以NextViewController 作为根视图控制器来实例化一个新的导航控制器。

    当我点击蓝色按钮时,同样的事情会尽早发生。我们将另一个NextViewController 添加到当前导航堆栈并且计数增加。当我们点击橙色时,我们正在查看一个新堆栈(注意导航控制器的内存地址现在不同)并且计数重置为 1。

    这是该屏幕截图中的代码:

    import UIKit
    
    class NextViewController: UIViewController {
        init() {
            super.init(nibName: "NextViewController", bundle: NSBundle.mainBundle())
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        override func viewWillAppear(animated: Bool) {
            super.viewWillAppear(animated)
            print("ViewCintroller:\(title) NavController:\(navigationController) stack size:\(navigationController?.viewControllers.count)")
        }
    
        @IBAction func showAnother() {
            navigationController?.pushViewController(NextViewController(), animated: true)
        }
    
        @IBAction func presentModally() {
            let anotherNavigationStack = UINavigationController(rootViewController: NextViewController())
            presentViewController(anotherNavigationStack, animated: true, completion: nil)
        }
    }
    

    请注意,蓝色的“添加另一个”按钮连接到 showAnother(),橙色的“呈现模态”按钮连接到 presentModally()

    这是日志中的一个示例:

    ViewCintroller:nil NavController:Optional(<UINavigationController: 0x7fa889810800>) stack size:Optional(8)
    ViewCintroller:nil NavController:Optional(<UINavigationController: 0x7fa88c057a00>) stack size:Optional(1)
    ViewCintroller:nil NavController:Optional(<UINavigationController: 0x7fa88c057a00>) stack size:Optional(2)
    ViewCintroller:nil NavController:Optional(<UINavigationController: 0x7fa88c057a00>) stack size:Optional(3)
    ViewCintroller:nil NavController:Optional(<UINavigationController: 0x7fa88c042800>) stack size:Optional(1)
    

    这些日志的第一行表示连续第 8 次点击蓝色按钮。第 2 行表示点击了橙色按钮。请注意,内存地址从0x7fa889810800 更改为0x7fa88c057a00。第 3 行和第 4 行代表点击蓝色按钮。我们注意到内存地址保持在0x7fa88c057a00,但导航计数增加到三(代表一个橙色点击,然后是两个蓝色点击)。然后对于第 5 行,我们点击了橙色按钮,内存地址再次从 0x7fa88c057a00 更改为 0x7fa88c042800,并且计数再次重置为 1。

    【讨论】:

    • 是的,但问题是,我没有以模态方式呈现其他视图控制器。我在所有视图控制器上使用相同的 show segue。但是系统从第 5 个视图控制器开始以模态方式呈现它们。当我使用已弃用的 push segue 而不是新的 show segue 时,一切正常!
    • 我编辑了我的问题,以表明使用已弃用的 push segues 在 4 个视图控制器之外也能按预期工作。唯一的问题是,情节提要显示转场不起作用。所以这可能不是 UINavigationController 的问题,而是故事板显示 segue 的问题。唯一的解决方案似乎是使用已弃用的 push segue,或者,正如您所演示的,以编程方式实例化新的视图控制器。
    • 我所做的任何程序调用都没有被弃用(或者你会在这些屏幕截图中看到黄色/红色标记)。我会仔细检查您是否绝对确定您以相同的方式正确连接了所有视图控制器。我的猜测是你没有像前四个一样连接第五个控制器。
    • 我绝对确定我在故事板中使用了独特的显示转场。这在故事板大纲视图中很容易看到。正如我上面所说的,当我将所有的 show segues 更改为已弃用的 push segues 时,一切正常。但是后来我把所有的 push segues 改回了 show segues,异常就消失了!现在所有的节目片段都可以正常工作了!
    • 我检查了一个具有相同问题的真实项目。我证实,所有的转场都是表演转场。 100%。但同样,另一个项目也表现出同样的异常:第 5 次转场导致了模态转场,尽管它是设置的。所以我改变了所有的显示序列来推送序列,编译并改回显示序列,再次编译,现在一切都按预期工作了!现在,我确定问题出在 Xcode Interface builder 上。无论如何,现在我知道如何解决这个问题了。但是 Xcode 的行为非常具有误导性。
    猜你喜欢
    • 1970-01-01
    • 2014-10-07
    • 2012-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-27
    • 1970-01-01
    相关资源
    最近更新 更多