使用协议强制限制视图模型 - AssociatedType/conditional-conformance/swift 更新更新 2更新 3

问题描述

protocol Identifiable {
  var id: String { get }
}
struct ModelA: Identifiable {
  var id: String
}
struct ModelB: Identifiable {
  var id: String
}
protocol ViewModelable {
  associatedtype model: Identifiable
}
struct ViewModelA: ViewModelable {
  typealias model = ModelA
}
class ViewA: UIView {
  var viewModel: ViewModelA
}
struct ViewModelB: ViewModelable {
 typealias model = ModelB
}
class ViewB: UIView {
  var viewModel: ViewModelB
}
class CustomListView: UIView {
  var viewModels<T: ViewModelable>: [T]?
  var viewmodels:[ViewModelable]
}

我需要对我的视图模型将持有的模型强制执行规则。但是 View1 中的语法会引发编译错误。 (协议 'ViewModelable' 只能用作通用约束,因为它具有 Self 或相关的类型要求)。那么我还有其他方法可以强制执行此操作吗?

我的用例:

自定义列表视图是一种容器视图,它将具有一个表视图并呈现视图(viewmodelA 和 viewmodelB)

解决方法

您可以在类型定义期间强制执行。

class View1<T: ViewModelable>: UIView {
  var viewmodels: [T] = []
}

许多标准 API 都这样做。

Array<Element>
Dictionary<Key: Hashable etc.

更新

要通过返回 id 的所有这些协议访问您的财产,您可以这样做。

protocol ViewModelable {
  associatedtype Model: Identifiable
  var model: Model { get }
}
struct ViewModelA: ViewModelable {
  typealias Model = ModelA
  var model: Model
}
struct ViewModelB: ViewModelable {
  typealias Model = ModelB
  var model: Model
}

class View1<T: ViewModelable>: UIView {
  var viewModels: [T] = []
  
  func doSomething() {
      let firstModelID = viewModels.first?.model.id
  }
}

更新 2

自定义列表视图是一种容器视图,它将具有一个表视图并呈现视图(viewmodelA 和 viewmodelB)

class CustomListView1<A: ViewModelable,B: ViewModelable>: UIView {
    var viewModelAs: [A] = []
    var viewModelBs: [B] = []
}

/// You can go one step further as well
class CustomListView2<A: ViewModelable,B: ViewModelable>: UIView 
where A.Model == ModelA,B.Model == ModelB {
    var viewModelAs: [A] = []
    var viewModelBs: [B] = []
}

更新 3

有 5 个以上的视图模型,并且所有视图模型都呈现在一个 tableview 中,因此无法将其保存在单独的数组中。

class View2: UIView {
    enum ViewModel {
        case viewModelA(ViewModelA)
        case viewModelB(ViewModelB)
        // Add as many variants as you want
        
        var model: Identifiable {
            switch self {
            case .viewModelA(let vma): return vma.model
            case .viewModelB(let vmb): return vmb.model
            }
        }
    }
    
    var viewModels: [ViewModel] = []
    
    func doSomething() {
        let firstModelID = viewModels.first?.model.id
    }

}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...