约束协议的关联类型本身

时间:2016-10-16 07:25:37

标签: ios swift generics associated-types

我正在尝试创建通用的CollectionView数据源。 我有两个协议,第一个 - 一些抽象单元格,第二个表示符合类可以由一些抽象单元格呈现,并且应该只包含引用该单元格的相关类型。它们的实现可能如下所示:

protocol EntityPresentingCell {

    // entity that should be presented in this cell
    associatedtype T

    static var CellReuseID: String { get }

    // takes object and fill UI with data
    func populate(with object: T)
}

protocol CellPresentable {

    // cell that should present this entity
    // I need to constrain it
    associatedtype Cell: EntityPresentingCell // where Cell.T == Self
}

class CollectionViewDataSource<T: CellPresentable>: NSObject, UICollectionViewDataSource {

    var items: [T]

    init(items: [T]) {
        self.items = items
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return items.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: T.Cell.CellReuseID, for: indexPath)

        // compiler error here since, obviously, T.Cell.T not constrained to T itself
        (cell  as! T.Cell).populate(with: items[indexPath.item])
        return cell
    }

}

在使用时它可能如下所示:

class SomeEntity: CellPresentable {
    typealias Cell = SomeEntityCell

    var someValue = "someValue"
}

class SomeEntityCell: EntityPresentingCell {

    static var CellReuseID: String = "SomeID"

    @IBOutlet weak var label: UILabel!

    func populate(with object: SomeEntity) {
        label.text = object.someValue
    }

}

这段代码的问题在于我无法限制(因此在编译时确保)CellPresentable.Cell.T等于CellPresentable本身(如示例中所示)。可以清楚地看到编译器错误。

目标是制作纯编译时足够的代码,以证明该项目可以通过给定的单元格呈现(再次,在编译时),并且我不想强迫向下转换,或任何其他运行 - 时间检查。

有可能吗?如果是这样,怎么样?

UPD:David Rodrigues answer有效,但这意味着只有在我即将创建(T.Cell.T != T)时才会显示不匹配CollectionViewDataSource。当我定义我的实体与EntityPresentingCell协议的一致性时,我希望它发生。换句话说,当我写

之类的东西时,编译器应该抱怨
class SomeEntity: CellPresentable {
    typealias Cell = SomeWrongEntityCell

    var someValue = "someValue"
}

但不是在创建CollectionViewDataSource实例时。确保细胞类型的实体责任,而不是CollectionViewDataSource的创建者。

2 个答案:

答案 0 :(得分:3)

Swift 4更新

您现在可以将protocol CellPresentable { associatedtype Cell : EntityPresentingCell where Cell.T == Self } 约束添加到关联类型中,因此您现在可以说:

where

Swift 3

目前,除了要求相关类型之外,还无法向关联类型添加任何进一步的约束。

但是,现在SE-0142: Permit where clauses to constrain associated types已被接受,在未来的Swift版本中,可以将protocol CellPresentable { associatedtype Cell : EntityPresentingCell where Cell.T == Self } 子句添加到关联类型。

能够说:

where T.Cell.T == T

虽然在实施此功能之前,添加通用约束float:left的{​​{3}}可能与您即将获得的一样好。

答案 1 :(得分:1)

您可以将T.Cell.T约束为T

class CollectionViewDataSource<T: CellPresentable>: NSObject, UICollectionViewDataSource where T.Cell.T == T