Swift 协议中的协议

Swift protocol inside of protocol

我 运行 遇到了 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 - 即使 FirstNameViewModelOnboardingPageViewModel.

我该如何解决这个问题?

使用关联类型 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
    }
}

您可以通过删除 associatedtype:

来解决您的页面数组
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 .