首页 > 解决方案 > 以 swift 事件序列在 tabController 下的 viewControllers 之间传递数据

问题描述

我有一个 UITabController Main,它有两个 UIViewController,A 和 B。在情节提要中。每个控制器都有一个对应的swift类,Main, A, B

Main.swift 是 UITabController 的子类和 UITabBarControllerDelegate 的委托。在它的 viewDidLoad 中,它设置了它的 .delegate = self。

在 Main 的 func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) 我捕获选定的选项卡,并采取行动设置一些我希望传递给选定 viewController 的变量 Y 的数据值。

在 ViewController 类 A 和 B 中,变量 Y 有一个 var 声明。

在每个 ViewController A 和 B 中,在 viewWillAppear 中,我从这个变量 Y 填充本地自定义视图出口。

它不起作用的原因是由于事件处理的顺序。

我假设当我点击tab时,首先处理Main的tabBarController函数,然后再处理选中的对应viewController的viewWillAppear。不是这种情况。

显然,首先执行所选(A 或 B)viewController 的 viewWillAppear,然后触发 Main 的 tabBarController。这当然会导致问题,因为我显示由 Y 填充的网点,然后我填充 Y ...

这种让 Main 用一些数据填充 A 或 B 的技术是首选的,因为 A 和 B 不应该知道彼此的任何信息。但是 Main 对 A 和 B 都有深入的了解。我真的不想进行单例/全局数据传递——我更喜欢干净地处理它。

有关如何更正此事件序列的顺序或建议另一种(正确的 MVC)技术的任何建议?

我的目标:我想将一些数据传递给所选选项卡下的视图层次结构,并让调用者进行传递。接收者视图层次结构应该忘记它是如何接收数据的。

(我有一个丑陋的解决方法,我会重新触发 viewWillappear,但基本上这会导致愚蠢的流程:A.viewWillAppear --> Main.tabBarController --> 强制另一个 A.viewWillAppear)

非常感谢。

代码(简化——现在这是一个已解决的工作示例)

class MainController: UITabBarController, UITabBarControllerDelegate {

override func viewDidLoad() {
    super.viewDidLoad()
    delegate = self;
}

 override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
    print ("tabBarController didSelect")
    let viewController = viewControllers![self.selectedIndex]
    if let vc = viewController as? AViewController {
        vc.Y = "some valuable data"
    }

    else if let vc = viewController as? BViewController {
        vc.Y = "some valuable data"
    }
}
}

class AViewController: UIViewController {


@IBOutlet weak var YTextField: UITextField!
var Y: String = ""

override func viewDidLoad() {
    super.viewDidLoad()
}


override func viewWillAppear(_ animated: Bool) {
    print ("viewWillAppear A")
    super.viewWillAppear(animated)

    YTextField.text = self.Y
}
}

class BViewController: UIViewController {

@IBOutlet weak var YTextField: UITextField!
var Y: String = ""

override func viewDidLoad() {
    super.viewDidLoad()
}


override func viewWillAppear(_ animated: Bool) {
    print ("viewWillAppear B")
    super.viewWillAppear(animated)

    YTextField.text = self.Y
}
}

标签: iosswiftuitabbarcontrollerviewwillappear

解决方案


您正在使用:

// this is called when the tab's ViewController is selected (*after* the tab item is selected (tapped))
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) { ... }

当你想使用:

// this is called *when* the tab item is selected (tapped)
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) { ... }

这是对您的示例的修改:

import UIKit

class MainViewController: UITabBarController, UITabBarControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        delegate = self;
    }

    override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {

        let n = self.selectedIndex

        if let tabControllers = viewControllers {

            if let _ = tabControllers[n] as? AViewController {
                // *current* VC is AViewController
                if let vcB = tabControllers[n + 1] as? BViewController {
                    vcB.Y = "some valuable data from A"
                }
            }

            else if let _ = tabControllers[n] as? BViewController {
                // *current* VC is BViewController
                if let vcA = tabControllers[n - 1] as? AViewController {
                    vcA.Y = "some valuable data from B"
                }
            }

        }

    }

}

class AViewController: UIViewController {

    @IBOutlet weak var YTextField: UITextField!

    var Y:String = ""

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        YTextField.text = Y
    }

}

class BViewController: UIViewController {

    @IBOutlet weak var YTextField: UITextField!

    var Y:String = ""

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        YTextField.text = Y
    }

}

您需要进行一些额外的处理/检查以确保您到达所需的选项卡。您可能希望在MainViewControlleron内部设置一个变量didSelect item,然后在“目标”视图控制器内部设置该变量 on didSelect viewController


推荐阅读