SwinjectStoryboard
SwinjectStoryboard 是 Swinject 的扩展,可以自动向由 storyboard 实例化的视图控制器注入依赖项。
需求
- iOS 8.0+ / Mac OS X 10.10+ / tvOS 9.0+
- Xcode 8+
安装
Swinject 可通过 Carthage 或 CocoaPods 获得。
Carthage
要在 Carthage 中安装 Swinject,请将以下行添加到您的 Cartfile
。
github "Swinject/Swinject"
github "Swinject/SwinjectStoryboard"
然后运行 carthage update --no-use-binaries
命令或只是 carthage update
。有关 Carthage 的安装和使用细节,请访问 其项目页面。
MacPods
要使用MacPods安装Swinject,请将以下几行添加到您的Podfile
文件中。
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0' # or platform :osx, '10.10' if your target is OS X.
use_frameworks!
pod 'Swinject'
pod 'SwinjectStoryboard'
然后运行pod install
命令。有关MacPods的安装和使用详情,请访问其官方网站。
Swift包管理器
要使用Apple的Swift包管理器集成,请在您的Package.swift
文件中将以下内容添加为依赖项。
.package(url: "https://github.com/Swinject/SwinjectStoryboard.git", .upToNextMajor(from: "2.2.0"))
然后指定"SwinjectStoryboard"
作为您希望使用SwinjectStoryboard的目标的依赖项。
使用方法
Swinject支持自动依赖注入,用于由SwinjectStoryboard
实例化的视图控制器。此类继承自UIStoryboard
(或OS X中的NSStoryboard
)。为注册视图控制器的依赖项,请使用storyboardInitCompleted
方法。就像注册服务类型一样,视图控制器可以带有或不带有名称进行注册。
注意:请不要显式解析由storyboardInitCompleted
方法注册的视图控制器。视图控制器将隐式由SwinjectStoryboard
解析。
注册
不带名称的注册
以下是一个注册视图控制器依赖项且不带注册名称的简单示例。
let container = Container()
container.storyboardInitCompleted(AnimalViewController.self) { r, c in
c.animal = r.resolve(Animal.self)
}
container.register(Animal.self) { _ in Cat(name: "Mimi") }
接下来,我们创建一个指定容器的SwinjectStoryboard
实例。如果没有指定容器,则使用SwinjectStoryboard.defaultContainer
。instantiateViewControllerWithIdentifier
方法会创建一个带有注入依赖项的视图控制器实例。
let sb = SwinjectStoryboard.create(
name: "Animals", bundle: nil, container: container)
let controller = sb.instantiateViewControllerWithIdentifier("Animal")
as! AnimalViewController
print(controller.animal! is Cat) // prints "true"
print(controller.animal!.name) // prints "Mimi"
类和协议所在的位置
class AnimalViewController: UIViewController {
var animal: Animal?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
protocol Animal {
var name: String { get set }
}
class Cat: Animal {
var name: String
init(name: String) {
self.name = name
}
}
同时,具有名称Animals.storyboard
的故事板包含具有故事板ID Animal
的 AnimalViewController
。
通过名称注册
如果故事板中存在多个相同类型的视图控制器,则应使用注册名称注册依赖项。
let container = Container()
container.storyboardInitCompleted(AnimalViewController.self, name: "cat") {
r, c in c.animal = r.resolve(Animal.self, name: "mimi")
}
container.storyboardInitCompleted(AnimalViewController.self, name: "dog") {
r, c in c.animal = r.resolve(Animal.self, name: "hachi")
}
container.register(Animal.self, name: "mimi") {
_ in Cat(name: "Mimi")
}
container.register(Animal.self, name: "hachi") {
_ in Dog(name: "Hachi")
}
然后,以类似不带注册名称的情况创建视图控制器实例。
let sb = SwinjectStoryboard.create(
name: "Animals", bundle: nil, container: container)
let catController = sb.instantiateViewControllerWithIdentifier("Cat")
as! AnimalViewController
let dogController = sb.instantiateViewControllerWithIdentifier("Dog")
as! AnimalViewController
print(catController.animal!.name) // prints "Mimi"
print(dogController.animal!.name) // prints "Hachi"
Dog
类所在的位置
class Dog: Animal {
var name: String
init(name: String) {
self.name = name
}
}
,同时,名为Animals.storyboard
的故事板包含具有故事板ID Cat
和 Dog
的 AnimalViewController
。除了故事板ID外,用户自定义的运行时属性也指定为键 swinjectRegistrationName
的 cat
和 dog
。
UIWindow和根视图控制器创建
从“主”故事板隐式创建
如果您隐式地从“Main”故事板创建UIWindow
及其根视图控制器,请将setup
类方法作为SwinjectStoryboard
的扩展实现以向defaultContainer
注册依赖项。当运行时实例化根视图控制器(初始视图控制器)时,将向注册到defaultContainer
的依赖项注入。
注意,Swift 4中这里强制要求使用@objc
属性。
extension SwinjectStoryboard {
@objc class func setup() {
defaultContainer.storyboardInitCompleted(AnimalViewController.self) { r, c in
c.animal = r.resolve(Animal.self)
}
defaultContainer.register(Animal.self) { _ in Cat(name: "Mimi") }
}
}
在AppDelegate中显式创建
如果您喜欢显式地创建UIWindow
及其根视图控制器,请在application:didFinishLaunchingWithOptions:
方法中使用具有容器的SwinjectStoryboard
创建实例。
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var container: Container = {
let container = Container()
container.storyboardInitCompleted(AnimalViewController.self) { r, c in
c.animal = r.resolve(Animal.self)
}
container.register(Animal.self) { _ in Cat(name: "Mimi") }
return container
}()
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
let window = UIWindow(frame: UIScreen.mainScreen().bounds)
window.makeKeyAndVisible()
self.window = window
let storyboard = SwinjectStoryboard.create(name: "Main", bundle: nil, container: container)
window.rootViewController = storyboard.instantiateInitialViewController()
return true
}
}
请注意,您应该删除应用程序的Info.plist
中的Main storyboard file base name
项(或如果您正在显示原始键/值,则是UIMainStoryboardFile
项)。
故事板参考
Xcode 7引人的故事板参考由SwinjectStoryboard
支持。为了使在从引用的故事板创建实例时启用依赖注入,请将依赖注册到SwinjectStoryboard
的静态属性defaultContainer
。
let container = SwinjectStoryboard.defaultContainer
container.storyboardInitCompleted(AnimalViewController.self) { r, c in
c.animal = r.resolve(Animal.self)
}
container.register(Animal.self) { _ in Cat(name: "Mimi") }
如果你隐式实例化UIWindow
及其根视图控制器,由于在setup
方法中配置了defaultContainer
,可以共享为“主”故事板设置注册。
面向维护者
创建新发布版本
我们的发布流程在Makefile中描述。运行make help
命令以获取更多信息。
致谢
SwinjectStoryboard受到以下灵感的启发
许可
MIT许可。请参阅LICENSE文件以获取详细信息。