【发布时间】:2020-10-31 15:03:02
【问题描述】:
所以我不知道标题是否正确解决了我的问题,但事情是这样的:
我有一个用于识别几种类型的表格视图单元格的枚举。每种类型的细胞都有自己的类。我已经使其中的每一个都符合协议,但具有关联的类型。我现在正在尝试创建一种方法来拥有这些类的实例并任意使用它们的协议方法和属性。这是一个例子:
enum CellType {
case a, b, c
func getCellClass() -> ProtocolWithAssociatedType.Type { //Error here
switch self {
case .a: return ClassA.self
case .b: return ClassB.self
case .c: return ClassC.self
}
}
此枚举在该行引发Protocol 'CreateOrderTableViewCellProtocol' can only be used as a generic constraint because it has Self or associated type requirements 错误。
所以这是我所拥有的确切协议,除了名称:
protocol ProtocolWithAssociatedType: UITableViewCell {
associatedtype Delegate
var delegate: Delegate? {get set}
func setupCell()
}
ClassA、ClassB 和 ClassC 的所有类都符合这一点。他们都有自己的委托协议,他们使用typealias 进行投射,例如:
protocol ClassADelegate: class {
...
}
class ClassA: UITableViewCell, ProtocolWithAssociatedType {
typealias Delegate = ClassADelegate
weak var delegate: ClassADelegate?
func setupCell() {}
...
}
extension ViewController: ClassADelegate {
...
}
所有这些都是为了瘦 tableView(...cellForItemAt:...) 和其他类似的方法,因为这个项目中有很多单元格类,它超出了可读性,真的很难做因此,对此特定视图控制器的任何开发。 我有一个 UITableView 的扩展,用于为那些可重复使用的单元格创建可重复使用的单元格,它的可重复使用 id 与它的类名称相同,如下所示:
func dequeueReusableCell<C>(_ cellType: C.Type, for indexPath: IndexPath) -> C where C: UITableViewCell {
let identifier = String(describing: cellType)
guard let cell = dequeueReusableCell(withIdentifier: identifier, for: indexPath) as? C else {
fatalError("Failed to find cell with identifier \"\(identifier)\" of type \"\(C.self)\"")
}
return cell
}
所以我愿意像下面这样使用它:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellType = CellDataArray[indexPath.row].cellType
let cellClass = cellType.getCellClass()
let cell = tableView.dequeueReusableCell(cellClass, for: indexPath) \\ Here I have to have the cell conform to the protocol somehow
cell.delegate = self \\So here is the associated type which doesn't need to be read but is need to be written only
cell.setupCell() \\Obviously there are going to be some data passed to the cell instance right here
return cell
}
我已经阅读了很多问题和答案,并且我正在尝试其中的每一个来实现这一点,但我无法做到。我试图避免视图控制器中的大量功能,并使事情尽可能可修改。所有这些单元格本身就像小视图控制器一样,它们都必须与视图控制器通信。单元格也不是静态的,就像在不同的场合,我必须展示不同的单元格。现在,即使添加一个简单的单元格也是一项艰巨的工作,更不用说创造一个全新的场合了。但是通过这种方法,我试图使事情......模块化。
那么有什么方法可以做到这一点,而不会在这里和那里出现运行时崩溃或创建黑洞并终结宇宙?
编辑:我尝试过通用类型的方式,但无法这样做。由于我希望 func getCellClass() 工作的方式,不可能让编译器知道该泛型类型是什么。如下:
func getCellClass<C>() -> C.Type where C: ProtocolWithAssociatedValue {
...
}
所以即使我强制将返回值强制转换为 C.Type,我也有问题,我只是因为 C 未知而调用它。
编辑
我已从协议中删除了相关值并执行了以下操作:
protocol ProtocolWithAssociatedType: UITableViewCell {
var _delegate: AnyObject? {get set}
func setupCell()
}
protocol ClassADelegate: class {
...
}
class ClassA: UITableViewCell, ProtocolWithAssociatedType {
weak var _delegate: AnyObject? { didSet { delegate = _delegate as? ClassADelegate } }
private weak var delegate: ClassADelegate?
func setupCell() {}
...
}
extension ViewController: ClassADelegate {
...
}
通过这种方式,协议可用作该枚举函数的返回类型,并且我可以强制将可重用单元格强制转换为它,因为协议本身符合 UITableViewCell。我已经构建没有任何问题但还不能测试(测试服务器在工作时间之外关闭)。当我测试它并且如果它运行没有任何问题时,我会将它作为解决方案发布。
【问题讨论】:
标签: ios swift uitableview swift-protocols