简体   繁体   中英

Swift - Should I use enum with Generic or create more than one initializer

I am currently facing a decision in the task I am working on. Let me give you some context. The screen Im working on is divided in 4 sections, each section has its own instance of my table view component , each with specific cells . All 4 table views are stacked in the screen. I created a Enum called SectionType and I use this information when Im instantiating the component like: CustomTableView(ofType: .type1) . In this way I can switch the enum inside the table view decide which cell Im going to use, how many cells...

Now I need to pass the data to the TableView, I created 4 Models and Im thinking how is the best way to use this in my component.


  • Solution 1: Creating Convenience inits for each SectionType

My enum:

enum SectionType {
    case news, analysis, lives, sectors
}

My Custom table:

private var newsData: [Model.Home.News]? = nil
private var analysisData: [Model.Home.Analysis]? = nil
private var livesData: [Model.Home.Lives]? = nil
private var sectorsData: [Model.Home.Sector]? = nil

// MARK: Initializers
private init(for tableViewType: SectionType) {
    self.tableViewType = tableViewType
    super.init(frame: .zero, style: .plain)
    delegate = self
    dataSource = self
    registerCells()
}
        
convenience init(for tableViewType: SectionType, with data: [Model.Home.News]) {
    self.init(for: tableViewType)
    self.newsData = data
}

convenience init(for tableViewType: SectionType, with data: [Model.Home.Analysis]) {
    self.init(for: tableViewType)
    self.analysisData = data
}

convenience init(for tableViewType: SectionType, with data: [Model.Home.Lives]) {
    self.init(for: tableViewType)
    self.livesData = data
}

convenience init(for tableViewType: SectionType, with data: [Model.Home.Sector]) {
    self.init(for: tableViewType)
    self.sectorsData = data
}

  • Solution 2: Creating a Generic Let and using Enum with parameters

Changing my Enum to:

enum SectionType {
    case news(data: [Model.Home.News])
    case analysis(data: [Model.Home.Analysis])
    case lives(data: [Model.Home.Lives])
    case sectors(data: [Model.Home.Sector])
}

And in my table do something like:

private var data: Array<T>? = nil

// Call this func at initialization
func setData(_ sextionType: SectionType) {
    switch sextionType {
    case .news(let data), .analysis(let data), .lives(let data), .sectors(let data):
        self.data = data
    }
}

I don't know if this solution is possible and how to make it work


  • Solution 3: Accepting suggestions from you guys

Please comment


Thank you for your attention S2

If you are going to have code inside your table view to determine which cells to use etc, the I don't see the point of trying to create a single subclass that does everything. You could just use inheritance; create a MyBaseTableView and then create specific subclasses MyNewsTableView: MyBaseTableView and so on.

Solution 1 definitely doesn't look good to me; You have four different potential data properties, only one of which will have value in a particular case. You will need to use a series of if statements to determine which one applies and you don't really end up achieving anything over having four separate table view classes.

Similarly, if you use generics with an enum you are still tightly binding the possible data sources with the table view.

If you did want to use generics then you don't need a enum . You can simply make your table view generic on its data type. You can use a protocol to allow your data to provide the cell information.
eg

protocol CellProvider {
    func provideCell(for tableView: UITableView, at indexPath: IndexPath)-> UITableViewCell
    static func registerCell(in tableView: UITableView)
}

class GenericTableView<T: CellProvider>: UITableView, UITableViewDataSource {
    var data: [T]
    
    init(data: [T]) {
        self.data = data
        super.init(frame: .zero, style: .plain)
        self.dataSource = self
        T.registerCell(in: self)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.data.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return self.data[indexPath.row].provideCell(for: self, at: indexPath)
    }
}


struct StringModel {
    var value: String
}

extension StringModel: CellProvider {
    
    static let cellName = "StringCell"
    
    func provideCell(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: Self.cellName, for: indexPath)
        cell.textLabel?.text = value
        return cell
    }
    
    static func registerCell(in tableView: UITableView) {
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellName)
    }
    
    
}

struct NumberModel {
    var value: Int
}

extension NumberModel: CellProvider {
    
    static let cellName = "StringCell"
    
    func provideCell(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: Self.cellName, for: indexPath)
        cell.textLabel?.text = "\(value)"
        return cell
    }
    
    static func registerCell(in tableView: UITableView) {
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellName)
    }
    
    
}

Now, when you create your table view you simply provide the data and the generics and protocol do the rest:

private var strings = [StringModel(value: "A"), StringModel(value:"B")]
private var numbers = [NumberModel(value: 1),NumberModel(value:2)]
//...

self.stringTV = GenericTableView(data: strings)

self.numberTV = GenericTableView(data: numbers)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM