Search code examples
iosswiftgenericsprotocol-oriented

How to make Base class property generic in swift so can use with multiple model type?


I want the property "cellViewModel" as generic so I can reuse BaseCustomCell with a different types of models. Ex.

 struct CELLVIEWMODEL {
   var name: String
   var address: String
 }
 class BaseCustomCell: UITableViewCell {
       var cellViewModel: CELLVIEWMODEL  //should support different model types CELLVIEWMODEL1,CELLVIEWMODEL2
       {
        didSet() {
          setValuesInSubClasses
        }
      }
      func setValuesInSubClasses() {
       //subclass will implement
      }
 }

 class subCell: BaseCustomCell {
     override func setValuesInSubClasses() {
       //set value from cellViewModel
      }
 }

//This is how i am setting from cellForRowAtIndexPath method:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: viewModel.getCellId(), for: indexPath) as! BaseCustomCell
        cell.cellViewModel = viewModel.getCellModelAtIndexPath(indexPath) //this will set values for subclasses
        return cell
    }

Now, I am creating new BaseCustomCell each time for different types of cellViewModel. Could you help with any solution?


Solution

  • There are several ways to achieve your goals.

    You can make the actual BaseCustomCell glass generic, but be aware if you use Storyboards, this isn't a solution, since you'd need to hardcode the generic type into the storyboard.

    The other solution that works with storyboards too is to declare your viewmodel as a protocol, then you can replace it with any concrete implementation of the protocol.

    protocol CellViewModel {
        var name: String { get }
        var address: String { get }
    }
    
    class BaseCustomCell: UITableViewCell {
        var cellViewModel: CellViewModel {
            didSet() {
                setValuesInSubClasses
            }
        }
        
        func setValuesInSubClasses() {
           //subclass will implement
        }
    }
    
    class SubCell: BaseCustomCell {
         override func setValuesInSubClasses() {
           //set value from cellViewModel
          }
     }
    

    And then your viewModel.getCellModelAtIndexPath should have a return type of CellViewModel, so it can return any type that conforms to the protocol.

    So you simply need to declare your concrete cell view models like class FirstCellViewModel: CellViewModel { ... }, etc. and you can return them from getCellModelAtIndexPath