我正在使用Swift开发一个iOS应用程序,该应用程序在组成该应用程序的大多数视图控制器中具有不同的状态。视图控制器所依赖的少数“状态”是用户是否登录,地址是否已注册,搜索或丢失等。目前,数据已在{中提供给视图控制器{1}}个方法。
以下是我的应用程序的结构,还有大约十二个具有类似结构的视图控制器。
prepare(for:sender)
App.swift
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
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
大约一年前,我第一次遇到“如何在视图控制器之间传递数据”时找不到的原始帖子,但这很可能是其中之一:Passing Data between View Controllers(在任何地方都提到术语依赖注入)。
然后,大约一个月前,我听说了这个术语“ 依赖注入”,这个花哨的词似乎很适合我处理需要处理的课程(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
}
和HomeViewController
)的情况可以具有状态(OtherViewController
)的数据。
为验证这种在序列中扔struct App
实例的方法,我做了几个晚上的研究。
但是现在我有太多有关以下内容的信息:several dependency injection methodologies,unit testing in swift via DI,一些DI框架here,here,here,{{3} },单元测试框架and here,here,以及(由于缺乏声誉,现在我无法添加更多链接。),以及大量的中级/博客/ SO帖子。< / p>
问题是:1. 我在这里做所谓的依赖注入吗?这是“正确的方法”吗? 2. 我可以吗? 3. 如果我在做的是合法依赖注入,为什么有人需要依赖注入框架?
至少对于我来说,依赖注入框架看起来没有必要,神秘(而且很可怕),至少对我来说,只是尝试编写遵循SOLID原则的可维护应用程序。 我已经厌倦了抽象概念或与情况无关的示例,因此,如果有人帮助我解决这些概念和设计决策(包括对框架的需求),我将感到非常高兴。
答案 0 :(得分:1)
我建议避免将重点放在不同类型的DI的技术细节上,而将重点放在基本概念上。 DI表示您的视图控制器本身无法获得所需的依赖关系,但是依赖关系是从 outside 提供的。
因此,您的otherVC.app = app
是DI的非常小的基本示例。
简而言之,您现在可以通过app
的不同实例测试视图控制器,这是进行DI的主要目标。
您能做得更好吗?我们可能会。例如,使您的App
对象更小一些,将“状态”分成更小的部分。
另一个改进可能是在视图控制器中使用协议而不是具体类型。这样,在测试期间,您可以将模拟对象作为依赖项传递,这对测试有很大帮助。
答案 1 :(得分:0)
我同意IgnazioC's answer,并希望添加一些内容。
我想您可以问这个问题,以了解您的实现是否是DI的一个很好的例子。
您的代码解决了您的问题。但是我认为(也许对此我错了)这会带来另一个问题。
从另一个viewController确定viewControllers的依赖关系是一个好主意吗?真的,这是viewController的工作吗?还是应该?在大多数情况下,我认为这不是一个好习惯。
当您有一个ViewController链展示自己并且大多数依赖项(例如用户信息)必须在该链的第一个和最后一个ViewController之间携带但不是全部时,会发生什么。这将创建一些复制代码。也许其中一些可以用复合模式或类似的模式来管理,但不能全部解决。
我认为(也许我又错了)在消费者之间进行依赖不是一个好主意。至少大部分。也许您将编写一个足够小的应用程序来管理此问题。但是大多数情况下,依赖关系应该在viewController链之外解决。
注意:我不包括从以前的contoller创建的依赖项,就像在主从场景中那样。他们是不同的东西。
此刻,这很难。也许swift需要一些改进才能更轻松地做到这一点(例如更好的反射器)。但是,我发现an atricle与Swift 5.1中的DI使用有关。我还没有用但这似乎是一个有用的解决方案。也许这可以帮助您。