Make a generic TableView DataSource class

1.2k Views Asked by At

I want to make a generic TableView DataSource class, that contains an array of ConfigureModel:

protocol ConfigureModel {
    associatedtype ModelType
    var name: String { get set }

    var modelDescription: String { get }
}

I also want the TableView cell to be generic:

class ConfigureCell<ConfigureType>: UITableViewCell, Configure {
    func configure<Model: ConfigureModel>(with value: Model) where ConfigureType == Model.ModelType {
        let description = value.modelDescription

        print("ConfigureCell description: \(description)")
    }
}

so I made ConfigureCell adopt the generic Configure protocol:

protocol Configure {
    associatedtype ConfigureType

    func configure<Model: ConfigureModel>(with value: Model) where Model.ModelType == ConfigureType
}

Now I can make a model adopt the ConfigureModel protocol to be able to be used in the ConfigureCell class:

struct Tag {
    ....
}
extension Tag: ConfigureModel {
    typealias ModelType = Tag
}

This works fine. Now to make the ObjectDataSource generic:

class ObjectDataSource<T: ConfigureModel>: NSObject, UITableViewDataSource, UITableViewDelegate {
    var values: [T] = []
    ....
    public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let item = self.values[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: "TagCell", for: indexPath) as! ConfigureCell<T>
        cell.configure(with: item)

and here I have a problem that I have tried for many hours to solve. The last cell.configure(with: item statement Xcode is showing the error: Instance method 'configure(with:)' requires the types 'T' and 'T.T' be equivalent

I understand that I have to make a generic where clause in the class, but I have trouble finding out what that should be.

class ObjectDataSource<T: ConfigureModel>: NSObject, UITableViewDataSource, UITableViewDelegate
    where T == ???? {

I have made a Xcode Playground which works, but the commented out parts doesn't work. You can get it here: GenericDataSource Xcode PlayGround

1

There are 1 best solutions below

1
nayem On BEST ANSWER

I also want the TableView cell to be generic

You simply don't need that. You already have defined the configure(with:) method to be a generic one. No need to make the class itself a generic one.


Given the above statement, if you're okay with it, here will be your implementation as simple as:

class ConfigureCell: UITableViewCell {
    func configure<Model: ConfigureModel>(with value: Model) {
        let description = value.modelDescription()

        print("ConfigureCell description: \(description)")
    }
}

class ObjectDataSource<T: ConfigureModel>: NSObject, UITableViewDataSource {
    var values: [T] = []

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return values.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let item = self.values[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: "TagCell", for: indexPath) as! ConfigureCell
        cell.configure(with: item)
        return cell
    }
}