我有一个名为TableViewItem
的协议。该协议强制符合标准的对象实现type
属性,该属性具有协议TableViewCellIdentifiable
作为其类型。 TableViewCellIdentifiable
用于将三个嵌套枚举分组在一起,如下所示:
internal protocol TableViewCellIdentifiable: Equatable { }
internal enum TableViewCellType {
internal enum PortfolioSelection: String, TableViewCellIdentifiable {
case portfolio = "portfolioTableViewCell"
case enterPortfolioDetails = "enterPortfolioDetailsTableViewCell"
case addPortfolio = "actionTableViewCell"
}
internal enum EditPortfolio: String, TableViewCellIdentifiable {
case editPortfolioName = "editPortfolioNameTableViewCell"
case deletePortfolio = "deletePortfolioTableViewCell"
}
internal enum Portfolio: String, TableViewCellIdentifiable {
case portfolioAsset = "portfolioAssetTableViewCell"
case addAsset = "actionTableViewCell"
}
}
以下是如何使用它的示例:
internal final class EditPortfolioNameTableViewItem: TableViewItem {
// MARK: - Internal Properties
internal let type: TableViewCellIdentifiable = TableViewCellType.EditPortfolio.editPortfolioName
internal let viewModel: TableViewCellModel
// MARK: - Initialization
internal init(viewModel: EditPortfolioNameTableViewCellModel) {
self.viewModel = viewModel
}
}
不幸的是,在声明type
属性的那一行上,我收到以下错误:
协议“ TableViewCellIdentifiable”只能用作一般约束,因为它具有“自我”或相关类型要求
我已经阅读了遇到此错误的其他人的其他问题/答案,但我不太明白为什么这种特殊的实现方式会带来问题,以及解决方案将是什么。我知道Equatable
是问题的根源,但这对功能至关重要,因为枚举有两个目的:
要允许比较类型-即:
self.tableViewItems.contains(where: { $0.type == item.type })
任何建议都将不胜感激,即使这意味着采取其他方法。
答案 0 :(得分:2)
在您脑海中,以下代码应该编译吗?
var x : Equatable
不应该。为什么?
因为您有:
var x : Equatable
var y : Equatable
然后,编译器无法确保x和y是同一类型。 x
可以是“ John”,因为“ John” /字符串是平等的……而y
可以是10
,因为10 /整数是平等的。
并且编译器会怀疑您可能想在下面几行
if x == y { print ("equal" }
它无法处理。因此,它一开始就阻止您进行此操作。
由于上述原因,下面的代码行将触发相同的错误。
internal let type: TableViewCellIdentifiable = TableViewCellType.EditPortfolio.editPortfolioName
答案 1 :(得分:1)
正如Honey的回答所解释的,TableViewCellIdentifiable
没有提供足够的类型信息供编译器使用。您可能会采用另一种方法,该方法会稍微改变结构(并可能会导致过大杀伤力),但会提供您正在寻找的功能:
internal protocol ValueAssociated { }
internal extension ValueAssociated {
fileprivate var association: (label: String, value: Any?)? {
get {
let mirror = Mirror(reflecting: self)
if let association = mirror.children.first, let label = association.label {
return (label, association.value)
}
return nil
}
}
}
internal protocol CellIdentifiable {
var rawValue: String { get }
}
internal enum CellType: Equatable, ValueAssociated {
case portfolio(PortfolioIdentifier)
case portfolioSelection(PortfolioSelectionIdentifier)
case editPortfolio(EditPortfolioIdentifier)
internal var identifier: String? {
return (self.association?.value as? CellIdentifiable)?.rawValue
}
internal enum PortfolioIdentifier: String, Equatable, CellIdentifiable {
case portfolioAsset = "portfolioAssetTableViewCell"
case addAsset = "actionTableViewCell"
}
internal enum PortfolioSelectionIdentifier: String, Equatable, CellIdentifiable {
case portfolio = "portfolioTableViewCell"
case enterPortfolioDetails = "enterPortfolioDetailsTableViewCell"
case addPortfolio = "actionTableViewCell"
}
internal enum EditPortfolioIdentifier: String, Equatable, CellIdentifiable {
case editPortfolioName = "editPortfolioNameTableViewCell"
case deletePortfolio = "deletePortfolioTableViewCell"
}
}
可以如下使用:
internal let cellType: CellType = .portfolio(.portfolioAsset)
print(cellType.identifier!) // Prints "portfolioAssetTableViewCell"
希望这会有所帮助。