如何使用 swinject 正确注入依赖项
How to proper inject dependency using swinject
我正在尝试使用 Swinject 注入依赖项,但我不知道我做错了什么。
我有处理注册字符串用户的协议。
protocol AuthServiceProtocol {
func registerUser(email: String, password: String, completion: @escaping CompletionHandler) }
和一个符合这个协议的class使得所有逻辑:
class AuthService: AuthServiceProtocol {
func registerUser(email: String, password: String, completion: @escaping CompletionHandler) {
let lowerCaseMail = email.lowercased()
let body: [String: Any] = [
"email": lowerCaseMail,
"password" : password
]
Alamofire.request(URL_REGISTER, method: .post, parameters: body, encoding: JSONEncoding.default, headers: HEADER).responseString { (response) in
if response.result.error == nil {
completion(true)
} else {
completion(false)
debugPrint(response.result.error as Any)
}
}
}
}
所以,在 AppDelegate 中我们注册容器,它看起来像:
let container = Container() { container in
container.register(AuthServiceProtocol.self) { _ in AuthService() }.inObjectScope(.container)
container.register(CreateAccountVC.self) { r in
let controller = CreateAccountVC()
controller.authService = r.resolve(AuthServiceProtocol.self)
return controller
}
}
但在 CreateAccountVC 中 authService 是空的。任何想法我该怎么做?
CreateAccountVC 是 ViewController 的子 class,我已经通过 属性 和构造函数尝试过它,但它一直都是零。
检查您的代码:
var container : Container {
let container = Container()
container.register(AuthServiceProtocol.self) { _ in AuthService() }.inObjectScope(.container)
container.register(CreateAccountVC.self) { r in
let controller = CreateAccountVC()
controller.authService = r.resolve(AuthServiceProtocol.self)
print(r.resolve(AuthServiceProtocol.self))
return controller
}
return container
}
您已计算 属性 并且每次调用它时,它都会创建一个新的 Container 对象。
重构您的代码以拥有单个容器,我相信您会顺利进行。
编辑:
这是一个有效的代码片段。
下面是一个小包装器 class 来抽象具体的 DI 服务(以防有一天 Swinject 被其他东西取代):
import Swinject
public class ConfigurationProvider {
// Currently using Swinject
private let backingService = Container()
// Singleton
public static let shared = ConfigurationProvider()
// Hidden initializer
private init() {}
// MARK: - Bind / Resolve
public func bind<T>(interface: T.Type, to assembly: T) {
backingService.register(interface) { _ in assembly }
}
public func resolve<T>(interface: T.Type) -> T! {
return backingService.resolve(interface)
}
}
// Extension methods to ignore 'shared.' call, like:
// ConfigurationProvider.bind(interface: IAssembly, to: Assembly())
// ConfigurationProvider.resolve(interface: IAssembly)
public extension ConfigurationProvider {
static func bind<T>(interface: T.Type, to assembly: T) {
ConfigurationProvider.shared.bind(interface: interface, to: assembly)
}
static func resolve<T>(interface: T.Type) -> T! {
return ConfigurationProvider.shared.resolve(interface: interface)
}
}
用法:
class RSAuthLoginModuleAssembly: IAuthLoginModuleAssembly {
}
// Register:
ConfigurationProvider.bind(interface: IAuthLoginModuleAssembly.self, to: ConcreteAuthLoginModuleAssembly())
// Resolve:
guard let assembly = ConfigurationProvider.resolve(interface: IAuthLoginModuleAssembly.self) else {
throw NSError(domain: "Assembly cannot be nil", code: 999, userInfo: nil)
}
我正在尝试使用 Swinject 注入依赖项,但我不知道我做错了什么。
我有处理注册字符串用户的协议。
protocol AuthServiceProtocol {
func registerUser(email: String, password: String, completion: @escaping CompletionHandler) }
和一个符合这个协议的class使得所有逻辑:
class AuthService: AuthServiceProtocol {
func registerUser(email: String, password: String, completion: @escaping CompletionHandler) {
let lowerCaseMail = email.lowercased()
let body: [String: Any] = [
"email": lowerCaseMail,
"password" : password
]
Alamofire.request(URL_REGISTER, method: .post, parameters: body, encoding: JSONEncoding.default, headers: HEADER).responseString { (response) in
if response.result.error == nil {
completion(true)
} else {
completion(false)
debugPrint(response.result.error as Any)
}
}
}
}
所以,在 AppDelegate 中我们注册容器,它看起来像:
let container = Container() { container in
container.register(AuthServiceProtocol.self) { _ in AuthService() }.inObjectScope(.container)
container.register(CreateAccountVC.self) { r in
let controller = CreateAccountVC()
controller.authService = r.resolve(AuthServiceProtocol.self)
return controller
}
}
但在 CreateAccountVC 中 authService 是空的。任何想法我该怎么做? CreateAccountVC 是 ViewController 的子 class,我已经通过 属性 和构造函数尝试过它,但它一直都是零。
检查您的代码:
var container : Container {
let container = Container()
container.register(AuthServiceProtocol.self) { _ in AuthService() }.inObjectScope(.container)
container.register(CreateAccountVC.self) { r in
let controller = CreateAccountVC()
controller.authService = r.resolve(AuthServiceProtocol.self)
print(r.resolve(AuthServiceProtocol.self))
return controller
}
return container
}
您已计算 属性 并且每次调用它时,它都会创建一个新的 Container 对象。
重构您的代码以拥有单个容器,我相信您会顺利进行。
编辑:
这是一个有效的代码片段。 下面是一个小包装器 class 来抽象具体的 DI 服务(以防有一天 Swinject 被其他东西取代):
import Swinject
public class ConfigurationProvider {
// Currently using Swinject
private let backingService = Container()
// Singleton
public static let shared = ConfigurationProvider()
// Hidden initializer
private init() {}
// MARK: - Bind / Resolve
public func bind<T>(interface: T.Type, to assembly: T) {
backingService.register(interface) { _ in assembly }
}
public func resolve<T>(interface: T.Type) -> T! {
return backingService.resolve(interface)
}
}
// Extension methods to ignore 'shared.' call, like:
// ConfigurationProvider.bind(interface: IAssembly, to: Assembly())
// ConfigurationProvider.resolve(interface: IAssembly)
public extension ConfigurationProvider {
static func bind<T>(interface: T.Type, to assembly: T) {
ConfigurationProvider.shared.bind(interface: interface, to: assembly)
}
static func resolve<T>(interface: T.Type) -> T! {
return ConfigurationProvider.shared.resolve(interface: interface)
}
}
用法:
class RSAuthLoginModuleAssembly: IAuthLoginModuleAssembly {
}
// Register:
ConfigurationProvider.bind(interface: IAuthLoginModuleAssembly.self, to: ConcreteAuthLoginModuleAssembly())
// Resolve:
guard let assembly = ConfigurationProvider.resolve(interface: IAuthLoginModuleAssembly.self) else {
throw NSError(domain: "Assembly cannot be nil", code: 999, userInfo: nil)
}