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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With