4

Better to ask with example. So its table sections and rows

First created a protocol which needs to be implemented by all rows which has an associated type, must be given by caller to tell while defining row.

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

So creating a generic row struct here

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
    }
}

Creating a different row struct here

struct DifferentRow<T>: RowElementProtocol {

    var cellIdentifier = "cell"
    var cellType: T

    /// Some Different Properties other then generic
}

Now creating a section which can have any kind of rows

struct Section<T: RowElementProtocol> {

    var rows = 1
    var rowElements: [T]
}

Everything is fine here, Problem arises when I want to initialise an array of sections

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

Compiler is not allowing me to initialise. Its showing ">' is not a postfix unary operator".

2 Answers 2

4

Let's have a look at the consequences of the compiler allowing you to create such an array.

You could do something like this:

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?

See the problem now? "Well, foo can just be of type Section<T: RowElementProtocol>" you might say. Okay, let's suppose that's true:

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

The compiler has no idea. It only knows that foo.rowElements[0] is "some type that conforms to RowElementProtocol but cellType could be anything.

"Okay, why not just use Any for that type?" you might ask. The compiler could do this, but that makes your generics pointless, doesn't it?

If you want to make your generics pointless, you can do what's called "type erasure", by creating the types AnyRowElement and 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)]
Sign up to request clarification or add additional context in comments.

Comments

0

You need to tell the compiler what the implemented type of T is

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

or like this

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

4 Comments

But now it's not generic any more. Now yours row associated type should always be String.
@AnoopRawat At some point you need to define the content. A better example than String would have been some (non-generic) protocol that all row elements need to implement.
Agree. But I want that point should be when someone appending value to the array. Or is it like, Section array must know what kind of elements are inside it.
@AnoopRawat yes it does and you do to so you know what properties you can access and what functions to call on the elements of the array

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.