我遇到了Swift协议的问题。我有这样的东西:
protocol OnboardingPage {
var viewModel: OnboardingPageViewModel! { get }
}
protocol OnboardingPageViewModel {
func getValue() -> Bool
}
// ---
class FirstNameViewController: UIViewController, OnboardingPage {
var viewModel: FirstNameViewModel!
}
class FirstNameViewModel: OnboardingPageViewModel {
func getValue() -> Bool {
return true
}
}
class GenderViewController: UIViewController, OnboardingPage {
var viewModel: GenderViewModel!
}
class GenderViewModel: OnboardingPageViewModel {
func getValue() -> Bool {
return false
}
}
我有一堆确认使用OnboardingPage
协议的视图控制器,并且它们都有一个都符合OnboardingPageViewModel
协议的视图模型。
但是可悲的是,上面的代码无法正常工作:它说FirstNameViewController
未确认OnboardingPage
协议,因为它的viewModel
属性的类型为FirstNameViewModel
而不是OnboardingPageViewModel
-即使FirstNameViewModel
是OnboardingPageViewModel
。
我该如何解决?
答案 0 :(得分:4)
使用关联类型 OnboardingPageViewModel类型ViewModel
已编辑
protocol OnboardingPage {
associatedtype ViewModel: OnboardingPageViewModel
var viewModel: ViewModel { get }
}
protocol OnboardingPageViewModel {
func getValue() -> Bool
}
class FirstNameViewController: OnboardingPage {
let viewModel: FirstNameViewModel
init(viewModel: FirstNameViewModel) {
self.viewModel = viewModel
}
}
class FirstNameViewModel: OnboardingPageViewModel {
func getValue() -> Bool {
return true
}
}
class GenderViewController: OnboardingPage {
let viewModel: GenderViewModel
init(viewModel: GenderViewModel) {
self.viewModel = viewModel
}
}
class GenderViewModel: OnboardingPageViewModel {
func getValue() -> Bool {
return false
}
}
答案 1 :(得分:0)
您可以删除关联类型来解决页面数组issue:
protocol OnboardingPage {
var viewModel: OnboardingPageViewModel { get }
}
protocol OnboardingPageViewModel {
func getValue() -> Bool
}
class FirstNameViewModel: OnboardingPageViewModel {
func getValue() -> Bool {
return true
}
}
class FirstNameViewController: OnboardingPage {
let viewModel: OnboardingPageViewModel
init(viewModel: FirstNameViewModel) {
self.viewModel = viewModel
}
}
class GenderViewModel: OnboardingPageViewModel {
func getValue() -> Bool {
return false
}
}
class GenderViewController: OnboardingPage {
let viewModel: OnboardingPageViewModel
init(viewModel: GenderViewModel) {
self.viewModel = viewModel
}
}
用法:
let nameModel = FirstNameViewModel()
let genderModel = GenderViewModel()
let array: [OnboardingPage] = [FirstNameViewController(viewModel: nameModel), GenderViewController(viewModel: genderModel)]
for page in array {
print(page.viewModel.getValue())
}
但是,以这种方式,您的模型的具体类型将对符合OnboardingPage
的类的调用者不可用。您可以尝试通过在OnboardingPage
内实施访客模式或增强其功能来解决该问题。
当然,您始终可以使用Cruz示例编写let pages: [Any] = [FirstNameViewController(), GenderViewController()]
,但是这样做很丑陋,如果可能,我强烈建议您不要在API中使用Any
。