如何快速创建通用关联类型协议的数组?

时间:2019-01-26 07:00:38

标签: ios swift xcode

更好地举例说明。所以它的表部分和行

首先创建了一个协议,该协议必须由具有关联类型的所有行实现,必须由调用方提供以在定义行时告知。

protocol RowElementProtocol {
    associatedtype ElementType
    var cellIdentifier: String {get set}
    var cellType: ElementType {get set}
}

因此在此处创建通用行结构

struct GenericRow <T>: RowElementProtocol {

    var cellIdentifier = "cell"
    var cellType: T

    /// Some Other Properties

    init(cellIdentifier: String = "cell", cellType: T) {

        self.cellIdentifier = cellIdentifier
        self.cellType = cellType
    }
}

在此处创建其他行结构

struct DifferentRow<T>: RowElementProtocol {

    var cellIdentifier = "cell"
    var cellType: T

    /// Some Different Properties other then generic
}

现在创建一个可以包含任何行的节

struct Section<T: RowElementProtocol> {

    var rows = 1
    var rowElements: [T]
}

这里一切都很好,当我要初始化一个节数组时会出现问题

let sections = [Section<T: RowElementProtocol>]()

编译器不允许我初始化。其显示的“>'不是后缀一元运算符”。

2 个答案:

答案 0 :(得分:0)

您需要告诉编译器T的实现类型是什么

let sections = [Section<GenericRow<String>>]()

或这样

typealias SectionType = Section<GenericRow<String>>
let sections = [SectionType]()

答案 1 :(得分:0)

让我们看一下允许您创建此类数组的编译器的结果。

您可以执行以下操作:

var sections = [Section<T: RowElementProtocol>]()
var sec1 = Section<GenericRow<String>>()
var sec2 = Section<DifferentRow<Int>>()
sections.append(sec1)
sections.append(sec2)
let foo = sections[0] // how can the compiler know what type this is?

现在看到问题了吗?您可能会说:“嗯,foo的类型可能是Section<T: RowElementProtocol>。”好吧,让我们假设这是真的:

foo.rowElements[0].cellType // what the heck is the type of this?

编译器不知道。它只知道foo.rowElements[0]是“符合RowElementProtocol的某种类型,但是cellType可以是任何东西。

“好的,为什么不对这种类型使用Any?”你可能会问。编译器可以做到这一点,但这使您的泛型毫无意义,不是吗?

如果想要使泛型变得毫无意义,则可以通过创建类型AnyRowElementAnySection来进行所谓的“类型擦除”:

struct AnyRowElement : RowElementProtocol {
    var cellIdentifier: String

    var cellType: Any

    typealias ElementType = Any

    init<T: RowElementProtocol>(_ x: T) {
        self.cellIdentifier = x.cellIdentifier
        self.cellType = x.cellType
    }
}

struct AnySection {
    var rows: Int
    var rowElements: [AnyRowElement]

    init<T: RowElementProtocol>(_ x: Section<T>) {
        self.rows = x.rows
        self.rowElements = x.rowElements.map(AnyRowElement.init)
    }
}

let sections: [AnySection] = [AnySection(sec1), AnySection(sec2)]