Dip-UI 2.0

Dip-UI 2.0

测试已测试
语言语言 SwiftSwift
许可 MIT
发布最后发布2017年9月
SwiftSwift 版本3.0
SPM支持 SPM

Ilya Puchka 维护。



Dip-UI 2.0

  • Ilya Puchka 和 Olivier Halligon

Dip-UI

Dip-UI 是 Dip 的扩展,它为使用故事板和 nib 文件的的应用程序提供依赖注入的支持。

安装

您可以使用您喜欢的依赖管理器安装 Dip-UI

CocoaPods

pod "Dip-UI"

要为 Swift 2.3 构建,请将以下代码添加到 Podfile 的底部

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['SWIFT_VERSION'] = '2.3'
    end
  end
end

您需要至少 1.1.0.rc.2 版本的 CocoaPods。

要为 Swift 2.3 构建,请使用 --toolchain com.apple.dt.toolchain.Swift_2_3 选项运行 Carthage。

使用方法

Dip-UI 提供了解决由故事板创建的视图控制器(或任何其他 NSObject)依赖关系的统一简单模式。

假设您想在 MyViewController 类中使用 Dip 注入依赖,该类定义如下

class MyViewController: UIViewController {
  var logger: Logger?
  var tracker: Tracker?
  var router: Router?
  var presenter: MyViewControllerPresenter?
  var service: MyViewControllerService?

  /*...*/
}

注意 1:虽然构造器注入是注入依赖的首选方式,但在此情况下我们无法使用它 - 我们无法让故事板使用自定义构造器。我们可以通过继承 UI:NSStoryboard 和方法适配来实现这一点,但您不会期望在 Swift 框架中看到这样的东西。

注意 2:在这里使用非可选隐式解包来表示这些依赖对该类是必需的。您不必遵循此模式,可以选择如果您喜欢,则可以使用纯可选值。

在从故事板实例化此视图控制器时,注入依赖的步骤如下

  • DependencyContainer 中注册依赖项,以及 MyViewController
import Dip

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

  let container = DependencyContainer { container in
    container.register(.Singleton) { LoggerImp() as Logger }
    container.register(.Singleton) { TrackerImp() as Tracker }
    container.register(.Singleton) { RouterImp() as Router }
    container.register { MyViewControllerPresenterImp() as MyViewControllerPresenter }
    container.register { MyViewControllerServiceImp() as MyViewControllerService }

    container.register(tag: "myVC") { MyViewController() }
      .resolvingProperties { container, controller in
        container.logger    = try container.resolve() as Logger
        container.tracker   = try container.resolve() as Tracker
        container.router    = try container.resolve() as Router
        container.presenter = try container.resolve() as MyViewControllerPresenter
        container.service   = try container.resolve() as MyViewControllerService
      }

      DependencyContainer.uiContainers = [container]
  }
}

注意:所有依赖项均注册为抽象(协议)的实现。将 MyViewController 注册为具体类型。但是,您也可以使您的视图控制器符合某些协议,并将它们注册为这些协议的实现。

  • 设置容器为用于注入到由故事板创建的对象中的依赖项的容器。您通过设置 DependencyContainer 类的静态 uiContainers 属性来完成此操作
DependencyContainer.uiContainers = [container]
  • 使您的视图控制器类符合 StoryboardInstantiatable 协议
extension MyViewController: StoryboardInstantiatable { }

提示:在组合根中这样做以避免将视图控制器代码与 Dip 框架耦合。

  • 在故事板(或 nib 文件)中,为您的视图控制器设置 Dip Tag 属性。这个值将被用来查找视图控制器的定义,所以它应该与您在容器中注册视图控制器时所使用的值相同。

img

注意:记住,如果 DependencyContainer 没有找到标记定义,它将回退到未标记的定义,因此您可以在没有标记的情况下注册您的视图控制器,但仍需要在一故事板中设置它。在这种情况下,您可以使用 Nil 属性类型而不是 String

现在,当视图控制器从故事板加载时,Dip-UI 将拦截 dipTag 属性的设置器,并要求 DependencyContainer.uiContainer 解析其依赖项。

StoryboardInstantiatable

StoryboardInstantiatable 协议定义了一个名为 didInstantiateFromStoryboard(_:tag:) 的单个方法,并提供了默认实现。在大多数情况下,您不需要重写它。但是,如果您将视图控制器注册为某些协议的实现而不是具体类型,或者想要执行一些前置/后置操作,您需要像这样重写它

container.register { MyViewController() as MyScene }
extension MyViewController: StoryboardInstantiatable {
  func didInstantiateFromStoryboard(container: DependencyContainer, tag: DependencyContainer.Tag?) throws {
    try container.resolveDependenciesOf(self as MyScene, tag: tag)
  }
}

许可证

Dip-UIMIT 许可证 下可用。有关更多信息,请参阅 LICENSE 文件。