gpt4 book ai didi

ios - 快速依赖注入(inject),具有两个 UIViewController 的依赖关系图,没有共同的父级

转载 作者:IT王子 更新时间:2023-10-29 05:48:30 24 4
gpt4 key购买 nike

当我们有两个在层次结构中非常深的 UIViewControllers 并且它们都需要保存状态的相同依赖项时,我们如何在不使用框架的情况下应用依赖注入(inject),而这两个 UIViewControllers 没有共同的父级。

例子:

VC1 -> VC2 -> VC3 -> VC4

VC5 -> VC6 -> VC7 -> VC8

让我们坐下来,他们都需要 VC4 和 VC8 UserService持有当前用户。

请注意,我们要避免单例。

有没有一种优雅的方法来处理这种 DI 情况?

经过一些研究,我发现有人提到了 Abstract Factory , Context interfaces , Builder , strategy pattern
但我找不到如何在 iOS 上应用它的例子

最佳答案

好的,我试试这个。

你说“没有单例”,所以我在下面排除了这一点,但也请看这个答案的底部。

Josh Homann 的评论已经是一个很好的解决方案的指针,但就我个人而言,我对协调器模式有疑问。

正如 Josh 正确说的那样, View Controller 不应该(很多)了解彼此 [1],但是如何例如传递/访问协调器或任何依赖项?有几种模式可以说明如何操作,但大多数模式都有一个基本上与您的要求背道而驰的问题:它们或多或少使协调器成为单例(本身或作为另一个单例的属性,如 AppDelegate )。协调器通常也被定义为单例(但并非总是如此,也不一定如此)。

我倾向于做的是依赖简单的初始化属性或 (最常见)懒惰的属性 和面向协议(protocol)的编程。让我们构建一个例子:UserService应是定义您的服务所需的所有功能的协议(protocol),MyUserService它的实现结构。让我们假设 UserService是一种设计结构,基本上用作某些用户相关数据的 getter/setter 系统:访问 token (例如保存在钥匙串(keychain)中)、一些首选项(头像图像的 URL)等。初始化时 MyUserService还准备数据(例如从远程加载)。这将用于多个独立的屏幕/ View Controller ,而不是单例。

现在每个有兴趣访问这些数据的 View Controller 都有一个简单的属性:

lazy var userService: UserService = MyUserService()

我将它公开是因为这允许我在单元测试中轻松模拟/ stub 它(如果我需要这样做,我可以创建一个模拟/ stub 行为的虚拟 TestUserService)。实例化也可以是一个闭包,如果 init 需要参数,我可以在测试期间轻松切换它。显然,这些属性甚至不一定需要是 lazy取决于对象的实际作用。如果提前实例化对象没有坏处(记住单元测试,还有传出连接),只需跳过 lazy .

绝招显然是到 设计UserService和/或 MyUserService以在创建它的多个实例时不会导致问题的方式 .但是,我发现这在 90% 的情况下并不是真正的问题,只要实例应该依赖的实际数据保存在其他地方,就一个事实而言,例如钥匙串(keychain),核心数据堆栈,用户默认值,或远程后端。

我知道这是一种逃避的答案,因为在某种程度上我只是在说描述一种方法(至少是其中的一部分)许多通用模式。然而,我发现这是在 Swift 中处理依赖注入(inject)的最通用和最简单的形式。协调器模式可以与其正交使用,但我发现它在日常使用中不太“像苹果”。它确实解决了一个问题,但大多数情况下,您没有按照预期正确使用 Storyboard(尤其是:只是将它们用作“VC 存储库”,从那里实例化它们并在代码中转换自己)。

[1] 除了一些基本的和/或次要的东西,你可以传入一个完成处理程序或 prepareForSegue .这是有争议的,取决于您遵循协调员或其他模式的严格程度。就个人而言,我有时会在这里走捷径,只要它不会使事情变得臃肿和变得凌乱。一些弹出式设计通过这种方式更简单。

作为结束语,“请注意,我们希望避免使用单例模式”以及您对此问题下的评论给我的印象是您只是遵循了该建议,而没有正确考虑其基本原理。我知道“Singleton”经常被认为是一种反模式,但这种判断也经常被误判。单例可以是一个有效的架构概念(您可以从它在框架和库中广泛使用的事实中看出这一点)。它的坏处只是它经常诱使开发人员在设计中走捷径并将其滥用为一种“对象存储库”,这样他们就不需要考虑何时何地实例化对象。这会导致模式困惑和声誉不佳。

一个 UserService ,取决于它在您的应用程序中实际执行的操作可能是单例的理想选择。我个人的经验法则是:“如果它管理某种独特而独特的东西的状态,比如在给定时间只能处于一种状态的特定用户”,我可能会选择单例。

特别是如果你不能按照我上面概述的方式设计它,即如果你需要内存中的单一状态数据,单例基本上是一种简单而正确的实现方式。 (即使使用(惰性)属性是有益的,您的 View Controller 甚至不需要知道它是否是单例,您仍然可以单独 stub /模拟它(即不仅仅是全局实例)。)

关于ios - 快速依赖注入(inject),具有两个 UIViewController 的依赖关系图,没有共同的父级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53560257/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com