Mejor preguntar con ejemplo. Entonces sus secciones de tabla y filas
Primero creó un protocolo que debe ser implementado por todas las filas que tienen un tipo asociado, debe ser proporcionado por la persona que llama para informar mientras define la fila.
protocol RowElementProtocol { associatedtype ElementType var cellIdentifier: String {get set} var cellType: ElementType {get set} }Entonces, creando una estructura de fila genérica aquí
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 } }Creando una estructura de fila diferente aquí
struct DifferentRow<T>: RowElementProtocol { var cellIdentifier = "cell" var cellType: T /// Some Different Properties other then generic }Ahora creando una sección que puede tener cualquier tipo de filas
struct Section<T: RowElementProtocol> { var rows = 1 var rowElements: [T] }Todo está bien aquí, surge un problema cuando quiero inicializar una serie de secciones
let sections = [Section<T: RowElementProtocol>]()El compilador no me permite inicializar. Está mostrando ">' no es un operador unario de postfijo".
Echemos un vistazo a las consecuencias de que el compilador le permita crear una matriz de este tipo.
Podrías hacer algo como esto:
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? ¿Ves el problema ahora? "Bueno, foo puede ser del tipo Section<T: RowElementProtocol> ", podría decir. Bien, supongamos que eso es cierto:
foo.rowElements[0].cellType // what the heck is the type of this? El compilador no tiene idea. Solo sabe que foo.rowElements[0] es "algún tipo que se ajuste a RowElementProtocol pero cellType podría ser cualquier cosa.
"Está bien, ¿por qué no usar Any para ese tipo?" podrías preguntar. El compilador podría hacer esto, pero eso hace que sus genéricos no tengan sentido, ¿no es así?
Si desea que sus genéricos no tengan sentido, puede hacer lo que se llama "borrado de tipo", creando los tipos AnyRowElement y AnySection :
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)]Debe decirle al compilador cuál es el tipo implementado de T
let sections = [Section<GenericRow<String>>]()o así
typealias SectionType = Section<GenericRow<String>> let sections = [SectionType]()