Reputation: 36317
This is just a mockup of my real example, my rows are complex objects
My tableview has different section types.
enum Type{
case devices
case users
case status
}
Obviously each section has some rows, may have a headerTitle and has a sectionType, I've tried to generalize that as much as I can. Not sure if using associatedType
is the right way...probably there's a much simpler solution for just using protocols
protocol SectionType{
associatedtype Section
associatedtype Rows
init(sectionType: Section, rows: Rows)
var sectionType: Section {get set}
var rows: Rows {get set}
var headerTitle: String? {get set}
}
The main problem is that is the rows of each Section can be entirely different (more than the difference between customObject1
and customObject2
) One solution is to just do var rows: Any
and then cast back, but that's not really a good idea.
class CustomObject1{
var number: Int
}
class CustomObject2{
var name : String?
}
My conformance to the protocol:
class SomeSection: SectionType{
var sectionType: Type
var rows: [CustomObject1]
var headerTitle: String?
required init(sectionType: Type, rows: [CustomObject1]){
self.sectionType = sectionType
self.rows = rows
}
}
As you can see my SomeSection
class is useless, it's only workable for
CustomObject1
var dataSource : [SectionType] = []
let firstSection = SomeSection(sectionType: .devices, rows: [CustomObject1(), CustomObject1(),CustomObject1()])
let secondSection = SomeSection(.users, rows: [???????]) // I can't add `CustomObject2` instances...nor I think creating a new class is a good idea
dataSource.append(firstSection)
dataSource.append(secondSection)
tableview.datasource = dataSource
How can I resolve this?
EDIT
I think my protocol approach was totally unnecessary. However now I have a different problem. My viewController was previously like:
class ViewController: UIViewController{
var dataSource : [Section] = []
}
now I have to change it to:
class ViewController<Row>: UIViewController{
var dataSource : [Section<Row>] = []
}
right?
The problem right now with the approach that Rich has suggested is that I can't apppend
these two instances of the Generic class into a single array, because their generic properties types are eventually not the same.
Upvotes: 3
Views: 108
Reputation: 3842
I think you can simplify the solution by using a generic class for this use case, but if you want to use protocols and associated types, the following should work:
protocol SectionType {
associatedtype Section
associatedtype Row
init(sectionType: Section, rows: [Row])
var sectionType: Section {get set}
var rows: [Row] {get set}
var headerTitle: String? {get set}
}
class SomeSection<T,U>: SectionType{
typealias Section = T
typealias Row = U
var sectionType: Section
var rows: [Row]
var headerTitle: String?
required init(sectionType: Section, rows: [Row]){
self.sectionType = sectionType
self.rows = rows
}
}
enum FoodType {
case cheese
case beer
}
enum Currency {
case dollars
case pounds
}
let s1 = SomeSection(sectionType: FoodType.cheese, rows: ["cheddar", "stilton"])
let s2 = SomeSection(sectionType: FoodType.beer, rows: ["rochefort12", "Spring Sprinter"])
let s3 = SomeSection(sectionType: Currency.dollars, rows: [1,2])
The generic version would just be:
class SomeSection<Section,Row> {
var sectionType: Section
var rows: [Row]
var headerTitle: String?
required init(sectionType: Section, rows: [Row]){
self.sectionType = sectionType
self.rows = rows
}
}
which might be better if the class isn't required to implement any other functionality
Upvotes: 4