Description
I have enums with case names that correspond to class names. I use the enum to populate sections/rows of a UITableView. When a user selects a row, I'd like to instantiate the corresponding class and instantiate an object of that class.
// example enum:
enum BodiceEnum: String, CaseIterable {
case AddBraCups
case AddOrRemoveBoning
// other cases hidden
}
// example classes:
class AddBraCups { // implementation hidden }
class AddOrRemoveBoning { // implementation hidden}
Additional Context
I made a lookup table to connect the "Section" enum cases to their corresponding detail enum cases:
var alterationsLookupTable: [(String,[Any])] = [
("Bodice",BodiceEnum.allCases),
("Neckline",NecklineEnum.allCases),
("Sides",SidesEnum.allCases),
("Sleeves or Straps",SleevesOrStrapsEnum.allCases),
("Back of Dress",BackOfDressEnum.allCases),
("Seams",SeamsEnum.allCases),
("Hem",HemEnum.allCases),
("Skirt",SkirtEnum.allCases),
("Veils",VeilsEnum.allCases),
("Prom - Straps",PromStrapsEnum.allCases),
("Prom - Take in/out",PromTakeInOrOutEnum.allCases),
("Prom - Hem",PromHemEnum.allCases),
("Tux",TuxEnum.allCases),
]
The current UITableView section corresponds to an index in this alterationsLookupTable
array.
Once I get the correct section's type, I switch over the corresponding enum cases for that section. I'm switching over itemsTuple.0
and then using the current indexPath.row value as an index in itemsTuple.1
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!
//var alterationDetailsArray: [String]()
let section = indexPath.section
var cellText: String = ""
let itemTuple = alterationsLookupTable[section]
switch itemTuple.0 {
case "Bodice":
let items = itemTuple.1 as! [BodiceEnum]
cellText = items[indexPath.row].readable
case "Neckline":
let items = itemTuple.1 as! [NecklineEnum]
cellText = items[indexPath.row].readable
case "Sides":
let items = itemTuple.1 as! [SidesEnum]
cellText = items[indexPath.row].readable
case "Sleeves or Straps":
let items = itemTuple.1 as! [SleevesOrStrapsEnum]
cellText = items[indexPath.row].readable
case "Back of Dress":
let items = itemTuple.1 as! [BackOfDressEnum]
cellText = items[indexPath.row].readable
case "Seams":
let items = itemTuple.1 as! [SeamsEnum]
cellText = items[indexPath.row].readable
case "Hem":
let items = itemTuple.1 as! [HemEnum]
cellText = items[indexPath.row].readable
case "Skirt":
let items = itemTuple.1 as! [SkirtEnum]
cellText = items[indexPath.row].readable
case "Veils":
let items = itemTuple.1 as! [VeilsEnum]
cellText = items[indexPath.row].readable
case "Prom - Straps":
let items = itemTuple.1 as! [PromStrapsEnum]
cellText = items[indexPath.row].readable
case "Prom - Take in/out":
let items = itemTuple.1 as! [PromTakeInOrOutEnum]
cellText = items[indexPath.row].readable
case "Prom - Hem":
let items = itemTuple.1 as! [PromHemEnum]
cellText = items[indexPath.row].readable
case "Tux":
let items = itemTuple.1 as! [TuxEnum]
cellText = items[indexPath.row].readable
default:
cellText = "not valid cell text"
}
cell.textLabel?.text = cellText
return cell
}
}
I've been looking at this but I can't seem to make it work. My (little) understanding of the problem is Swift's type safety. I'm guessing there is Swifty (idiomatic) way to make this happen.
Update 2:
Here’s an example of one Alteration Section —> Hem
and one of it’s subclasses —> AddHemLace
class Hem : Codable {
var minCost: Float
var maxCost: Float
var actualCost: Float
var name: String {
let thisType = type(of: self)
return String(describing: thisType)
}
init(minCost: Float, maxCost: Float, actualCost: Float) {
self.minCost = minCost
self.maxCost = maxCost
self.actualCost = actualCost
}
convenience init() {
self.init(minCost: -1, maxCost: -1, actualCost: -1)
}
}
class AddHemLace : Hem {
var costDetails: String?
var costUnit: String?
var units: Int = 1
var secondaryCost: Float = 0.0
var secondaryCostDetails: String?
var totalCost : Float {
return self.actualCost * Float(self.units) + self.secondaryCost
}
init() {
let min: Float = 50.00
let max: Float = 80.00
let actual: Float = min
super.init(minCost: min, maxCost: max, actualCost: actual)
}
required init(from decoder: Decoder) throws {
fatalError("init(from:) has not been implemented")
}
}
Problem: I couldn’t figure out how to populate the UITableView
I made related enumerations that had a parallel structure to my classes.
enum AlterationSectionsEnum: String, CaseIterable {
case Hem
// other cases
}
enum HemEnum: String, CaseIterable {
case cutAndReplaceHem
// other cases
}
I then used a big switch statement, a lookup table and some string parsing foo to fill the UITableView. Lots of code smell.
Question
As I attempt to understand this answer, I’m seeing now it would have been possible to use my classes directly to populate the UITableView.
I’m not sure where to start with this statement:
“For example, it should provide a method to populate an NSView or table cell. This way, each class can define its own kind of UI to present for its particular configurable parameters…”