我正在研究依赖注入,目前正在更新我的项目以利用它。但是,我遇到了相关类型和协议符合的问题。
我创建了一个快速演示项目,并创建了一些协议和扩展,以便符合我的协议ViewModelBased的viewControllers必须实现一个关联类型。理想情况下,我希望此关联类型符合viewModel。这是我到目前为止所拥有的
protocol ViewModel {
associatedtype Services
init (withServices services: Services)
}
protocol ViewModelBased: class {
associatedtype ViewModelType
var viewModel: ViewModelType { get set }
}
extension ViewModelBased where Self: UIViewController{
static func instantiateController(with viewModel : ViewModelType) -> Self {
// I have created UIStoryboard extension to allow for easy opening of view controllers
// in storyboard
let viewController : Self = UIStoryboard.mainStoryboard.instantiateViewController()
viewController.viewModel = viewModel
return viewController
}
}
因此,我的应用程序中的所有viewModel都符合ViewModel,强制它们实现服务类型。例如,我的LoginModel看起来像这样
struct LoginModel : ViewModel{
// service type
typealias Services = LoginService
// init service
var services : LoginService
init(withServices services: LoginService) {
self.services = services
}
/// calls login service - attempts login api
func attemptLogin() {
services.login()
}
}
所以这是一个实现这个
的viewController的例子class SecondController: UIViewController, ViewModelBased {
var viewModel: LoginModel!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func loginTest() {
viewModel.services.onLoginSuccess = { isVerified in
print(isVerified)
}
viewModel.services.onLoginFailure = { errorCode in
print(errorCode)
}
viewModel.attemptLogin()
}
}
所以把它放在一起,这允许app启动一个viewController并传入一个像这样的viewModel
let loginModel = LoginModel(withServices: LoginService())
let controller = SecondController.instantiateController(with: loginModel)
self.navigationController?.pushViewController(controller, animated: true)
这一切都很有效,但我遇到的问题是,相关的Type目前可以是任何类型。理想情况下,我希望此associatedType符合ViewModel协议。但是当我尝试这个时
protocol ViewModelBased: class {
associatedtype ViewModelType : ViewModel
var viewModel: ViewModelType { get set }
}
我的SecondController现在抛出一个错误,现在强迫我初始化LoginModel
var viewModel : LoginModel = LoginModel(withServices: LoginService())
但是这不再使用依赖注入,因为viewController现在负责创建viewModel实例并且知道viewModel类的行为。
我有办法解决这个问题吗?如果有人能给我一些关于我做错的信息,我将非常感激。
答案 0 :(得分:1)
您可以将Optional
扩展为有条件地符合ViewModel
:
extension Optional: ViewModel where Wrapped: ViewModel {
typealias Services = Wrapped.Services
init(withServices services: Services) {
self = Wrapped(withServices: services)
}
}
现在,您的SecondController
将其模型声明为var viewModel: LoginModel?
,默认情况下会将其初始化为nil
,同时仍确保其ViewModelType
为ViewModel
实际上需要创建它的实例。