【问题标题】:Dependency injection into UITabBarController child ViewControllers依赖注入到 UITabBarController 子 ViewControllers
【发布时间】:2016-02-03 20:27:55
【问题描述】:

我目前正在为 iOS 设置一个标签栏应用程序。

通常,我会在更改 viewControllers 时使用像 prepareforSeque 这样的重写方法进行依赖注入,但是当 UITabBarController 更改其活动子 ViewController 时不会调用该方法。如何正确地对 UITabBarController 子 ViewControllers 进行依赖注入?

【问题讨论】:

  • UITabBarControllerDelegate 协议有一个方法叫tabBarController(_:didSelectViewController:)

标签: ios swift xcode7


【解决方案1】:

在 RootViewController 的 viewDidLoad 中,您可以遍历 childViewControllers 并找到您想要的各种子控制器并将依赖关系设置为每个子控制器。在这种情况下,依赖项将在子视图控制器的 viewDidLoad 中可用。选项卡栏实例化子视图控制器实例,但直到需要时才加载视图。

加载标签栏视图控制器后,您可以使用委托方法注入更新的依赖项并在viewDidAppear 中使用它,因为一旦在标签栏中选择viewDidLoad,就不会调用它。

【讨论】:

  • 遍历视图控制器非常适合解决 viewDidLoad() 问题。感谢您的帮助!
  • 介意分享一些代码示例吗?简化的,伪的,随便的:)
【解决方案2】:

通过一些额外的研究,我想出了一个答案。感谢Will-m 提供我需要的线索。当前对此答案的警告是 TabBarController 加载的第一个视图不会被注入。

为了从 UITabBarController 向 ViewControllers 注入数据,您需要执行以下操作:

首先,您需要在加载时将 RootViewController 设置为自己的委托。

您不一定需要控制器类作为它自己的委托 除非您需要将所需数据从另一个类直接注入到 UITabBarController。

您还需要将委托类声明为符合UITabBarControllerDelegate 协议。

// Declare UITabBarControllerDelegate protocol
class RootViewController: UITabBarController, UITabBarControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Set class delegate to self
        self.delegate = self
    }
}

您需要设置 RootViewController 的委托,因为 委托的协议包含一个重要的方法: tabBarController(_:shouldSelectViewController:)。这种方法是 当 RootViewController 更改其活动选项卡时调用。

tabBarController(_:shouldSelectViewController:) 的“viewController”参数是 TabBarController 切换到的子 ViewController 的实例。如果您已为该 ViewController 分配了协议(以便编译器知道您的变量已在类中声明),您可以将变量注入子级。

所以像这样将函数添加到 RootViewController 类中:

func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) {
    // Get your view controller using the correct protocol.
    // Use guard to make sure the correct type of viewController has been provided.
    guard let vc = viewController as? YourProtocol
        else { fatalError("wrong view controller type") }
    // Assign the protocol variable to whatever you want injected into the class instance.
    vc.VariableInYourProtocol = InjectedVariable
}

就是这样。如果您需要支持不同协议的控制器,我可能会写一些关于使用 switch 语句来做到这一点的东西。那 到目前为止,这还不是我需要使用的东西。

另外,请注意,此方法适用于 CoreData 实践,其中只有一个 managedObjectContext 实例在活动 ViewController 之间传递。使用此方法而不是直接从每个 ViewController 的应用程序委托中检索上下文的不同实例。

【讨论】:

  • 如果您需要子视图控制器的 viewDidLoad 中的 InjectedVariable 是否有效?如果在 didSelectViewController 委托之前调用子视图控制器的 viewDidLoad 会发生什么?另一种选择是在您的子视图控制器类中使用静态变量,然后在更改为子视图控制器之前设置该变量。然后,您将在子视图控制器中的任何位置拥有依赖关系。然后,您可以将变量设置为 nil 以指示您已经使用了依赖项。关于如何做到这一点的另一个想法。
  • 目前,没有,但我正在研究如果 viewDidLoad 中需要该变量,还有哪些其他可用选项。目前,在加载视图后调用 tabBarController(_:didSelectViewController:) 。我要试试你的方法,看看是否有效。
  • 这取决于你的标签栏控制器和子视图控制器是如何设置的。您是在情节提要中创建整个视图控制器层次结构还是动态创建?如果您在情节提要中执行此操作,则首先实例化第一个视图控制器或标签栏控制器的 selectedIndex。在这种情况下,不调用委托。仅当您手动选择委托时才会调用它。如果您需要 viewDidLoad 中的变量而不是默认子 VC,那么您不能在委托中设置它。您可以遍历子 VC 并设置依赖项。
  • 更新:看起来函数 tabBarController(_:shouldSelectViewController:) 的使用更合适。在显示视图之前调用它。唯一需要注意的是标签栏控制器显示的第一个视图没有注入。
  • 请看我的回答,看看是否适合您的解决方案。我想会的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 2012-01-03
  • 2011-04-08
  • 2014-06-12
相关资源
最近更新 更多