如何在Swift中测试与associatedType协议的一致性?

时间:2017-06-12 21:03:52

标签: ios swift generics swift-protocols associated-types

我一直在尝试做一些允许用户将特定模型“附加”到特定单元格的代码。我打算用协议和associatedType方法做到这一点。

这是计划:

单元格可以显示数据时符合MTZSectionRowConfigurable,但它们不一定需要:

public protocol MTZSectionRowConfigurable {
    associatedtype T: MTZSectionRowModel
    func configure(with model: T?)
}

通过使用typealias,他们允许用户定义他们将代表哪个模型:

class SignOutCell: UITableViewCell, MTZSectionRowConfigurable {
    typealias T = SignOutModel
    var redLabel: UILabel!
    // ...
    func configure(with model: SignOutCellModel?) {
        self.redLabel.text = model?.text
    }
}

模型只需符合MTZSectionRowModel即可明确声明兼容性。

但是,由于代表模型是可选的,我需要在调用configure方法之前检查单元格是否支持它们。这是在cellForRowAtIndexPath:

上完成的
if let cell = cell as? MTZSectionRowConfigurable {
    cell.configure(with: sectionRow.model)
}

在上面的示例中,sectionRow.model属于MTZSectionRowModel?类型。

上面的代码无法编译。它产生了臭名昭着的:

  

“协议'MTZSectionRowConfigurable'只能用作通用约束,因为它具有Self或相关类型要求”

我试图检查单元格是否也响应#selector,但不幸的是同样的错误也适用。

有没有办法让这段代码有效?我错过了什么吗?我可以删除associatedType,使用广泛的MTZSectionRowModel在每个单元格上实现方法,但是我需要在每个实现中进行转换,但在我看来这不是最佳解决方案。

1 个答案:

答案 0 :(得分:0)

我知道你要做什么,我自己做了。但是,它比你现在所做的更为复杂。你在Andy Matuschak的gist中找到答案。

为了与SO答案的最佳实践保持一致,我将解释为什么这样做。让我们从结束开始吧。 cellForRow...这是objc func,需要返回UITableViewCell?。所以我们已经知道,我们将在某些时候丢失类型信息(即你的SignOutCell类不是返回的,它是它的超类,UITableViewCell)。鉴于我们最终得到了UITableViewCell,我们如何做您想做的事情并生成SignOutCell并进行配置?答案在于定义安迪在他的要点(在此链接)中描述的CellFactory中的完成处理程序。然后他使用bridgedDataSource从一种细胞类型转换为另一种细胞类型。我自定义了他的代码,允许根据输入参数返回4种不同类型的单元格。例如,我的UITableViewController可能包含4个UITableViewCell项,每个项的布局和数据模型都非常不同。我会参数化CellFactory以接受enum CellType,其中我预先定义了4种类型。然后,在单元工厂中,我使用switch cellType来设置单元格(此时我拥有单元格和模型数据的所有类型信息)。最后,bridgedDataSource返回良性UITableViewCell,使UIKit非常高兴,并且具备我需要的所有品质。安迪所依赖的一个基本概念是分解。我相信他有一个YouTube视频,或者在他的网站上有一个视频,他可以通过这个视频。如果我这样做的话,我会看看能否找到并更新答案。