我发现了一些针对此编译错误消息的StackOverflow问题,但没有一个答案对我有帮助。
从一开始,我就定义了一个ViewModel协议:
protocol FormVMProtocol: FormCellVMsProvider {
associatedtype RequestModel: GatewayObjectRequestModel
weak var delegate: EventFromVMDelegate? { get set }
var handleDidCancelForm: (() -> ())? { get set }
var handleDidAcceptForm: ((RequestModel) -> ())? { get set }
var title: String { get }
var cellsViewModels: [EventFormCellVMProtocol] { get }
var numberOfRows: Int { get }
func viewModelForRow(at indexPath: IndexPath) -> EventFormCellVMProtocol
func handleDidSelectRow(at indexPath: IndexPath)
func getIndexPath(for rowViewModel: EventFormCellVMProtocol) -> IndexPath?
func refreshRow(with viewModel: EventFormCellVMProtocol)
func refreshAllRows()
func createRequestModel() -> Promise<RequestModel>
func cancelForm()
func sendForm() -> Promise<()>
}
带扩展名:
extension FormVMProtocol {
var numberOfRows: Int {
return cellsViewModels.count
}
func viewModelForRow(at indexPath: IndexPath) -> EventFormCellVMProtocol {
return cellsViewModels[indexPath.row]
}
func handleDidSelectRow(at indexPath: IndexPath) {
viewModelForRow(at: indexPath).onSelected?()
}
func cancelForm() {
handleDidCancelForm?()
}
func sendForm() -> Promise<()> {
return createRequestModel()
.then {
self.handleDidAcceptForm?($0)
}
}
func getIndexPath(for rowViewModel: EventFormCellVMProtocol) -> IndexPath? {
guard let index = cellsViewModels.index(where: { rowViewModel === $0 }) else { return nil }
return IndexPath(row: index, section: 0)
}
func refreshRow(with viewModel: EventFormCellVMProtocol) {
guard let indexPath = getIndexPath(for: viewModel) else { return }
delegate?.reloadRow(at: indexPath)
}
func refreshAllRows() {
delegate?.reloadAllRows()
}
}
然后我创建了ViewController:
final class AddEventFormVC: BaseTileVC {
private var bottomButtonsStackView: UIStackView!
private var cancelButton: CustomButton!
private var acceptButton: CustomButton!
private var tableView: UITableView!
private let viewModel: FormVMProtocol
init(viewModel: FormVMProtocol) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
buildUI()
viewModel.delegate = self
}
}
///REST OF VC IS NOT IMPORTANT FOR THIS QUESTION
现在,我的想法是创建大量FormVMProtocol
子类并将它们注入AddEventFormVC
以重用一次创建的VC。
例如(其中一个):
final class NoteEventFormVM: FormVMProtocol {
typealias RequestModel = NoteEvent.InsertRequestModel
weak var delegate: EventFromVMDelegate?
var handleDidCancelForm: (() -> ())?
var handleDidAcceptForm: ((RequestModel) -> ())?
private let databaseHelper: DatabaseHelperProtocol
private let authorizationService: AuthorizationServiceProtocol
private lazy var noteTypeCellVM: EventFormSelectedValueCellVM<AddEventNoteTypeSelectionModel> = {
return provideFormSelectedValueCellVM(title: "Note Type".localized)
}()
private lazy var commentCellVM: EventFormStringDataCellVM = {
return provideFormStringDataCellVM(title: "Comment".localized)
}()
private lazy var eventDateCellVM: EventFormDateCellVM = {
return provideFormDateCellVM(title: "Event Date")
}()
lazy var cellsViewModels: [EventFormCellVMProtocol] = {
return [noteTypeCellVM, commentCellVM, eventDateCellVM]
}()
var title: String {
return "Notes".localized
}
init(databaseHelper: DatabaseHelperProtocol,
authorizationService: AuthorizationServiceProtocol) {
//INIT
}
func createRequestModel() -> Promise<RequestModel> {
//PROVIDE RequestModel
}
}
我想注意,我在此处将associatedtype
指定为NoteEvent.InsertRequestModel
使用示例:
let vm: FormVMProtocol
switch eventType {
case .note:
vm = NoteEventFormVM()
default:
//rest of event types
}
vm.handleDidCancelForm = { [weak self] in
let _ = self?.navigationController.popViewController(animated: true)
}
let eventFromVC = AddEventFormVC(viewModel: vm)
navigationController.pushViewController(eventFromVC, animated: true)
在我的AddEventFormVC
编译器中说
Protocol 'FormVMProtocol' can only be used as a generic constraint because it has Self or associated type requirements
我不知道如何满足编译器。
@Jack,FormCellVMsProvider
有助于构建cellVM。我认为在这种情况下并不重要,但您可以检查一个实现:
protocol FormCellVMsProvider: class {
func reloadSelectionValueCellVM<T>(_ cellVM: EventFormSelectedValueCellVM<T>, using fetchMethod: () -> Promise<[T]>, selectInitalValue: Bool) -> Promise<()>
func provideFormDateCellVM(title: String) -> EventFormDateCellVM
func provideFormSelectedValueCellVM<T: SelectionDialogRenderable>(title: String) -> EventFormSelectedValueCellVM<T>
func provideFormStringDataCellVM(title: String) -> EventFormStringDataCellVM
}
好的,我取得了一些成就。我将我的VC改为通用版:
final class AddEventFormVC<T: FormVMProtocol>: BaseVC {
private let viewModel: T
init(viewModel: T) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// REST OF VC
}
编译允许我以这种方式使用它:
let vm = NoteEventFormVM()
let vc = EventFormVC(viewModel: vm)
navigationController.pushViewController(vc, animated: true)
还有一个问题。我无法利用协议:
let vm: FormVMProtocol
vm.handleCancel = { //CODE }
vm.handleSuccess = { //CODE }
switch eventType {
case .note:
vm = NoteEventFormVM()
case .custom:
vm = CustomEventFromVM()
default:
//rest of event types
}
let vc = AddEventFormVC()
navigationController.pushViewController(vc, animated: true)
因为在行let vm: FormVMProtocol
中编译器正在喊Protocol <NAME> can only be used as a generic constraint because it has Self or associated type requirements
我需要通过案例复制/通过我的代码:
switch eventType {
case .note:
let vm = NoteEventFormVM()
vm.handleCancel = { //CODE }
vm.handleSuccess = { //CODE }
let vc = AddEventFormVC()
navigationController.pushViewController(vc, animated: true)
case .custom:
let vm = CustomEventFromVM()
vm.handleCancel = { //CODE }
vm.handleSuccess = { //CODE }
let vc = AddEventFormVC()
navigationController.pushViewController(vc, animated: true)
default:
//rest of event types
}
我正在寻找更好的解决方案。