Обрабатывать события в подпредставлениях в MVVM в Swift - PullRequest
2 голосов
/ 25 октября 2019

Я пытаюсь попасть в MVVM в Swift, и мне интересно, как обрабатывать события в подпредставлениях в MVVM и как эти события могут перемещаться вверх по цепочке представлений / моделей представления. Сейчас я говорю о чистом Swift (без SwiftRx и т. Модель представления содержит массив объектов и создает TableCellViewModel для каждого, поскольку каждая ячейка представляет один из этих объектов. TableViewController получает количество отображаемых строк из своей модели, а также модель представления для каждой ячейки, поэтому он может передать ее в ячейку.

Затем у нас есть TableCell, и каждая ячейка имеетTableCellViewModel. TableCell запрашивает в своей модели такие вещи, как строки, обращенные к пользователю и т. Д.

Теперь, скажем, TableCell также имеет кнопку удаления, которая удаляет эту строку. Мне интересно, как с этим справиться: Обычно ячейка перенаправляет нажатие кнопки на свою модель просмотра, но это не то место, где нам это нужно - нам в конечном итоге нужно знать о нажатии кнопки либо в TableViewController, либо в TableViewModelТаким образом, мы можем удалить строку из табличного представления.

Итак, вопрос:
Как происходит событие кнопки от TableCell вверх в цепочке представления в MVVM?

Код

В соответствии с просьбой в комментариях, код, который идет с примером:

class TableViewController: UIViewController, UITableViewDataSource {

    var viewModel: TableViewModel = TableViewModel()

    // setup and such

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableCell
        cell.viewModel = self.viewModel.cellViewModel(at: indexPath.item)
        return cell
    }

}

class TableViewModel {

    // setup, get data from somewhere, ...

    var count: Int {
        return self.modelObjects.count
    }

    func cellViewModel(at index: Int) -> TableCellViewModel {
        let modelObject = self.modelObjects[index]
        let cellViewModel = TableCellViewModel(modelObject: modelObject)
        return cellViewModel
    }

}

class TableCell {

    var viewModel: TableCellViewModel!

    // setup UI, do what a cell does

    func viewModelChanged() {
        self.titleLabel.text = self.viewModel.title()
    }

    func deleteButtonPressed(_ sender: UIButton) {
        // Oh, what to do, what to do?
    }

}

class TableCellViewModel {

    private var modelObject: ModelObject

    init(modelObject: ModelObject) {
        self.modelObject = modelObject
    }

    func title() -> String {
        return self.modelObject.title
    }

}

Ответы [ 2 ]

1 голос
/ 25 октября 2019

TableViewModel является источником правды, поэтому все глобальные операции должны выполняться там. Нажатие кнопки является полностью пользовательским интерфейсом, и viewModel не должен обрабатывать это напрямую.

Итак, на данный момент мы знаем два факта:

  1. TableViewModel следует удалить ячейку измассив, а затем viewController должен обрабатывать процесс удаления анимации;
  2. Нажатие кнопки не должно обрабатываться в дочернем viewModel.

В соответствии с этим вы можете достичь этого с помощью:

  1. Передача события нажатия кнопки до viewController (используйте шаблон обратного вызова или делегата);
  2. Вызов TableViewModel метод для удаления определенной ячейки:

    viewModel.deleteCell(at: indexPath)

  3. Правильно обрабатывать анимацию удаления в viewController.

0 голосов
/ 26 октября 2019

может быть, вы можете использовать nextResponder util nextResponder - это VC, а VC-респондент - делегат (например, CellEventDelegate), который обрабатывает удаление данных и ячейки

UIResponder *nextResponder = pressedCell.nextResponder;
        while (nextResponder) {
            if ([nextResponder conformsToProtocol:@protocol(CellEventDelegate)]) {
                if ([nextResponder respondsToSelector:@selector(onCatchEvent:)]) {
                    [((id<CellEventDelegate>)nextResponder) onCatchEvent:event];
                }
                break;
            }
            nextResponder = nextResponder.nextResponder;
        }
...