关于ios:依赖注入的建议以快速查看控制器

Suggestions for dependency injection to view controllers in swift

我正在使用Swift开发一个iOS应用程序,该应用程序在组成该应用程序的大多数视图控制器中具有不同的状态。视图控制器所依赖的少数"状态"是用户是否登录,地址是否已注册,搜索或丢失等。当前,数据以prepare(for:sender)方法。

以下是我的应用程序的结构,还有大约十二个具有类似结构的视图控制器。

App.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct App {
  enum LoginState {
    case unregistered
    case registered(User) // User defined elsewhere
  }

  enum OtherState {
    case stateOne
    case stateTwo(AssociatedType)
    case stateThree(OtherAssociatedType)
  }

  // Default states
  var loginState: LoginState = .unregistered
  var otherState: OtherState = .stateOne
}

HomeViewController.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class HomeViewController: UIViewController {
  var app: App!

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    super.prepare(for: segue, sender: sender)

    switch segue.identifier {
    case"Other View Controller Segue":
      let otherVC = segue.destination as! OtherViewController
      otherVC.app = app

    default:
      break
    }
}

AppDelegate.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
class AppDelegate: UIResponder, UIApplicationDelegate {
  var window: UIWindow?
  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let storybard = UIStoryboard(name:"Main", bundle: nil)
    let mainNavController = storyboard.instantiateViewController(withIdentifier:"Main Navigation Controller") as! UINavigationController
    let homeViewController = mainNavController.topViewController as! HomeViewController

    window?.rootViewController = mainNavController
    // 'injecting' app to the homeViewController
    homeViewController.app = App()

    return true
}

大约一年前,当我第一次遇到"如何在视图控制器之间传递数据"时,我找不到原始的帖子,但这很可能是其中之一:在视图控制器之间传递数据(这不会在视图控制器之间传递)。在任何地方都提到"依赖项注入"一词。
然后大约一个月前,我听说了这个术语依赖注入,这个花哨的术语似乎适合我处理需要处理可能具有状态(struct App)数据的类(HomeViewControllerOtherViewController)的情况。

为了验证这种在??segue中扔app实例的方法,我做了几个晚上的研究。
但是现在,我的信息太多了:几种依赖注入方法,通过DI快速进行单元测试,这里,这里,这里和这里的一些DI框架,这里,这里和这里的单元测试框架(现在我可以了)由于缺乏声誉而无法添加更多链接..),以及大量的中级/博客/ SO帖子。

问题是:1.我在这里进行所谓的依赖注入吗,这是"正确的方法"吗? 2.我可以使用这种方法进行单元/ UI测试吗? 3.如果我正在做的是合法的依赖注入,为什么一个人需要一个依赖注入框架?

依赖注入框架看起来是不必要的,神秘的((和令人恐惧的)),至少对我而言,只是尝试编写遵循SOLID原则的可维护应用程序。
我已经厌倦了抽象概念或与情况无关的示例,因此,如果有人帮助我解决这些概念和设计决策(包括对框架的需求),我将感到非常高兴。


我建议避免将注意力集中在不同类型的DI的技术细节上,而将重点放在基本概念上。 DI意味着您的视图控制器本身无法获得所需的依赖关系,但是依赖关系是从外部提供的。
因此,您的otherVC.app = app是DI的非常小的基本示例。

简而言之,您现在可以测试传递不同app实例的视图控制器,这是进行DI的主要目标。

你能做得更好吗?我们可能会。例如,使您的app对象更小一些,将"状态"分成较小的部分。
另一个改进可能是在视图控制器中使用协议而不是具体类型。这样,在测试期间,您可以将模拟对象作为依赖项传递,这对测试有很大帮助。


我同意IgnazioC的回答,并希望添加一些内容。

我想您可以问这个问题,以了解您的实现是否是DI的一个很好的例子。

  • 我可以获取任何我的consumer(viewController)并以我从外部设置的新依赖项运行它吗?如果答案是肯定的。对于DI来说,这是一个好习惯。
  • 我可以轻松地做到这一点,并且可以轻松编写所需的代码来使用它。该答案决定您的练习有多好。

您的代码解决了您的问题。但是我认为(这可能是我错了),这会带来另一个问题。

  • 从另一个viewController确定一个viewControllers的依赖关系是一个好主意吗?真的,这是viewController的工作吗?还是应该这样?在大多数情况下,我认为这不是一个好习惯。

  • 当您有一个ViewController链展示自己并且大多数依赖项(例如用户信息)必须在该链的第一个和最后一个ViewController之间(而不是全部)之间进行时,会发生什么情况。这将创建一些复制代码。也许其中一些可以用复合模式或类似的东西来管理,但不是全部。

我认为(也许我又错了)在消费者之间进行依赖不是一个好主意。至少大部分。也许您将编写一个足够小的应用程序来管理此问题。但是大多数情况下,依赖关系应该在viewController链之外解决。

注意:我不包括从以前的contoller创建的依赖项,就像在主从场景中发生的那样。他们是不同的东西。

此刻,这很难。也许swift需要一些改进才能更轻松地做到这一点(例如更好的反射器)。但是,我发现在Swift 5.1中有一些关于DI使用的信息。我还没有用但这似乎是一个有用的解决方案。也许这可以帮助您。