如何使用 swinject 正确注入依赖项
Posted
技术标签:
【中文标题】如何使用 swinject 正确注入依赖项【英文标题】:How to proper inject dependency using swinject 【发布时间】:2017-10-16 11:13:32 【问题描述】:我正在尝试使用 Swinject 注入依赖项,但我不知道我做错了什么。
我有处理注册用户的协议。
protocol AuthServiceProtocol
func registerUser(email: String, password: String, completion: @escaping CompletionHandler)
和一个符合这个协议的类组成了所有的逻辑:
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 的子类,我已经通过属性和构造函数尝试过它,但它一直是 nil。
【问题讨论】:
【参考方案1】:检查您的代码:
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 对象。
重构您的代码以拥有一个 Container,我相信您会很顺利。
编辑:
这是一个工作代码 sn-p。 下面是一个用于抽象具体 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)
【讨论】:
好的,如果我理解我必须调用在应用程序的整个生命周期中创建一个容器的函数? 没错。您为/从特定的 Container 对象注册/解析。 您现在可以检查容器代码吗?我只实例化了一次,它仍然是 nil.. 你能分享一下你解析对象并返回 nil 的代码吗? 所以如果我在容器中解决它,并在一行中覆盖它是不好的?我还应该在其他任何地方解决它吗? CreateAccountVC 中的 authService 是公开的。以上是关于如何使用 swinject 正确注入依赖项的主要内容,如果未能解决你的问题,请参考以下文章
Swinject:如何将委托模式与接口隔离(类与接口)一起使用?
如何将正确的 viewModel 注入单个 viewController
如何使用 Spring 将依赖项注入 HttpSessionListener?
如何使用 Typhoon 为集成测试注入虚假、存根或模拟依赖项