我使用了 KooberApp 的示例项目(它是 Raywenderlich 书籍高级架构示例项目),并尝试使用某些框架替换自定义的控制容器反转和依赖注入代码。我认为最流行的 iOS 依赖注入框架是 Swinject。在那里我可以为服务注册组件。我想类似于原始应用程序组件的生命周期。经过一番运行和尝试,应用程序似乎可以正常工作。但我不能 100% 确定我使用的方法是最好的,并且我没有错过重要的事情。我认为我仍然可以与组件生命周期存在一些不一致,即使用范围 .container、.graph、.transient、.weak
我有人可以建议这个 Container 实现是否正确,或者应该修复、更改、修改、做得更好?
应用容器
import Swinject
import SwinjectAutoregistration
public class DIAppContainer {
public class func get() -> Container {
let container = Container()
container.register(Container.self, name: "main") { r in
return DIMainContainer.get(parent: container)
}
container.autoregister(UserSessionCoding.self, initializer: UserSessionPropertyListCoder.init)
container.autoregister(AuthRemoteAPI.self, initializer: FakeAuthRemoteAPI.init)
#if USER_SESSION_DATASTORE_FILEBASED
container.autoregister(UserSessionDataStore.self, initializer: FileUserSessionDataStore.init)
#else
container.autoregister(UserSessionDataStore.self, initializer: KeychainUserSessionDataStore.init)
#endif
container.autoregister(UserSessionRepository.self, initializer: KooberUserSessionRepository.init)
container.autoregister(MainViewModel.self, initializer: MainViewModel.init).inObjectScope(.container)
container.register(LaunchViewModel.self) { r in
return LaunchViewModel(userSessionRepository: r.resolve(UserSessionRepository.self)!, notSignedInResponder: r.resolve(MainViewModel.self)!, signedInResponder: r.resolve(MainViewModel.self)!)
}.inObjectScope(.transient)
container.register(LaunchViewController.self) { r in
let vc = LaunchViewController(viewModel: r.resolve(LaunchViewModel.self)!)
return vc
}
container.register(MainViewController.self) { r in
let vc = MainViewController( viewModel: r.resolve(MainViewModel.self)!,
launchViewController: r.resolve(LaunchViewController.self)!,
mainContainer: r.resolve(Container.self, name: "main")! )
return vc
}
return container
}
}
主容器
public class DIMainContainer {
public class func get(parent: Container) -> Container {
let container = Container(parent: parent, defaultObjectScope: .container)
container.register(Container.self, name: "onboarding") { r in
return DIOnboardingContainer.get(parent: container)
}
container.register(Container.self, name: "signedin") { r in
return DISignedInContainer.get(parent: container)
}
container.autoregister(OnboardingViewModel.self, initializer: OnboardingViewModel.init).inObjectScope(.weak)
container.register(OnboardingViewController.self) { r in
return OnboardingViewController(viewModel: r.resolve(OnboardingViewModel.self)!, onboardingContainer: r.resolve(Container.self, name: "onboarding")! )
}.inObjectScope(.transient)
container.autoregister(SignedInViewModel.self, initializer: SignedInViewModel.init).inObjectScope(.weak)
container.register(SignedInViewController.self) { (r : Resolver, userSession : UserSession) in
return SignedInViewController(viewModel: r.resolve(SignedInViewModel.self)!, userSession: userSession, signedinContainer: r.resolve(Container.self, name: "signedin")!)
}.inObjectScope(.transient)
return container
}
}
登录容器
public class DISignedInContainer {
public class func get(parent: Container) -> Container {
let container = Container(parent: parent)
container.register(Container.self, name: "pickmeup") { r in
return DIPickMeUpContainer.get(parent: container)
}
//container.autoregister(SignedInViewModel.self, initializer: SignedInViewModel.init)
container.autoregister(ImageCache.self, initializer: InBundleImageCache.init)
container.autoregister(Locator.self, initializer: FakeLocator.init)
// Getting Users Location
container.register(DeterminedPickUpLocationResponder.self) { r in
return r.resolve(SignedInViewModel.self)!
}
container.register(GettingUsersLocationViewModel.self) { r in
return GettingUsersLocationViewModel(determinedPickUpLocationResponder: r.resolve(DeterminedPickUpLocationResponder.self)!, locator: r.resolve(Locator.self)!)
}
container.register(GettingUsersLocationViewController.self) { r in
return GettingUsersLocationViewController(viewModel: r.resolve(GettingUsersLocationViewModel.self)!)
}
// Pick Me Up
container.register(PickMeUpViewController.self) { (r: Resolver, location: Location) in
return PickMeUpViewController(location: location, pickMeUpContainer: r.resolve(Container.self, name: "pickmeup")! )
}
// Waiting For Pickup
container.register(WaitingForPickupViewModel.self) { r in
return WaitingForPickupViewModel(goToNewRideNavigator: r.resolve(SignedInViewModel.self)!)
}
container.register(WaitingForPickupViewController.self) { r in
return WaitingForPickupViewController(viewModel: r.resolve(WaitingForPickupViewModel.self)!)
}
// Profile
container.register(NotSignedInResponder.self) { r in
return r.resolve(MainViewModel.self)!
}
container.register(DoneWithProfileResponder.self) { r in
return r.resolve(SignedInViewModel.self)!
}
container.register(ProfileViewModel.self) { (r: Resolver, userSession: UserSession) in
return ProfileViewModel(userSession: userSession, notSignedInResponder: r.resolve(NotSignedInResponder.self)!, doneWithProfileResponder: r.resolve(DoneWithProfileResponder.self)!, userSessionRepository: r.resolve(UserSessionRepository.self)!)
}
container.register(ProfileContentViewController.self) { (r: Resolver, userSession: UserSession) in
return ProfileContentViewController(viewModel: r.resolve(ProfileViewModel.self, argument: userSession)!)
}
container.register(ProfileViewController.self) { (r: Resolver, userSession: UserSession) in
return ProfileViewController(contentViewController: r.resolve(ProfileContentViewController.self, argument: userSession)!)
}
return container
}
}
入职容器
public class DIOnboardingContainer {
public class func get(parent: Container) -> Container {
let container = Container(parent: parent)
container.register(GoToSignUpNavigator.self) { r in
return r.resolve(OnboardingViewModel.self)!
}
container.register(GoToSignInNavigator.self) { r in
return r.resolve(OnboardingViewModel.self)!
}
container.autoregister(WelcomeViewModel.self, initializer: WelcomeViewModel.init).inObjectScope(.transient)
container.autoregister(WelcomeViewController.self, initializer: WelcomeViewController.init).inObjectScope(.weak)
container.register(SignedInResponder.self) { r in
return r.resolve(MainViewModel.self)!
}
container.register(SignInViewModel.self) { r in
return SignInViewModel(userSessionRepository: r.resolve(UserSessionRepository.self)!, signedInResponder: r.resolve(SignedInResponder.self)!)
}.inObjectScope(.transient)
container.autoregister(SignInViewController.self, initializer: SignInViewController.init).inObjectScope(.transient)
container.register(SignUpViewModel.self) { r in
return SignUpViewModel(userSessionRepository: r.resolve(UserSessionRepository.self)!, signedInResponder: r.resolve(SignedInResponder.self)!)
}.inObjectScope(.transient)
container.autoregister(SignUpViewController.self, initializer: SignUpViewController.init)
return container
}
}
这里 App Container 是在 AppDelegate 中创建的,子容器在父容器中注册并 init 注入到视图控制器中,然后存储在属性中并用于初始化这个子视图控制器
let container : Container = DIAppContainer.get()
这是注入子容器(Main-Scoped)的 MainViewController 示例
// MARK: - Main-Scoped Container
let mainContainer: Container
// MARK: - Properties
// View Model
let viewModel: MainViewModel
// Child View Controllers
let launchViewController: LaunchViewController
var signedInViewController: SignedInViewController?
var onboardingViewController: OnboardingViewController?
// State
let disposeBag = DisposeBag()
// MARK: - Methods
public init(viewModel: MainViewModel,
launchViewController: LaunchViewController,
mainContainer: Container) {
self.viewModel = viewModel
self.launchViewController = launchViewController
self.mainContainer = mainContainer
super.init()
}