Как сделать свойство базового класса универсальным в swift, чтобы его можно было использовать с несколькими типами моделей?

#ios #swift #generics #protocol-oriented

#iOS #swift #дженерики #ориентированный на протокол

Вопрос:

Я хочу, чтобы свойство «cellViewModel» было общим, чтобы я мог повторно использовать BaseCustomCell с различными типами моделей. Например.

  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
      }
 }
  

// Вот как я настраиваю из метода cellForRowAtIndexPath:

 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
    }
  

Теперь я каждый раз создаю новую BaseCustomCell для разных типов cellViewModel. Не могли бы вы помочь с каким-либо решением?

Ответ №1:

Существует несколько способов достижения ваших целей.

Вы можете сделать фактический BaseCustomCell glass универсальным, но имейте в виду, что если вы используете раскадровки, это не решение, поскольку вам нужно будет жестко закодировать общий тип в раскадровке.

Другое решение, которое также работает с раскадровками, — объявить вашу viewmodel как протокол, затем вы можете заменить его любой конкретной реализацией протокола.

 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
      }
 }
  

И тогда у вас viewModel.getCellModelAtIndexPath должен быть возвращаемый тип CellViewModel , чтобы он мог возвращать любой тип, соответствующий протоколу.

Итак, вам просто нужно объявить ваши конкретные модели представления ячеек, например class FirstCellViewModel: CellViewModel { ... } , и т. Д., И Вы можете вернуть их из getCellModelAtIndexPath

Комментарии:

1. Я не использую раскадровку. Для меня это выглядит хорошо, можете ли вы добавить еще несколько объяснений, пожалуйста.

2. @AvijitNagare не уверен, что еще я могу объяснить, не вдаваясь в более конкретную проблему. Как я уже сказал, просто объявите тип cellViewModel в качестве протокола, viewModel.getCellModelAtIndexPath укажите возвращаемый тип протокола, затем внутри реализации getCellModelAtIndexPath вы можете возвращать конкретные типы моделей представления в зависимости от того, какие у вас есть критерии.

3. Не удалось установить значения для типа протокола CellViewModel в подклассе, поскольку я объявил CellViewModel(базовый протокол) со свойствами not. но у моего подкласса есть свойства, и мне необходимо обновить cellViewModel(чьи свойства не совпадают с базовыми cellViewModel). любое решение для этого.

4. @AvijitNagare просто приведите cellViewModel к конкретному типу, используя cellViewModel as? YourType