Предоставление реализации по умолчанию для переопределенного метода UIViewController, но только если контроллер соответствует протоколу

В моем приложении у меня было много стандартного кода, который мне приходилось писать всякий раз, когда в каком-то контроллере был UITableView. Чтобы устранить это, я создал BaseTableViewController, который реализует некоторые неоднократно используемые UITableDataSource такие операции, как tableView(_:numberOfRowsInSection:) а также tableView(_:cellForRowAt:), В tableView(_:numberOfRowsInSection:), мой BaseTableViewController извлекает фактическое количество строк в разделе из другого метода (давайте назовем его rowCount(inSection:)) и выполняет некоторые вычисления, используя его, затем возвращает результат делегирующему вызывающему. Каждый подкласс класса BaseTableViewController должен переопределить rowCount(inSection:) метод и возвращает правильное количество строк в данном разделе (сам BaseTableViewController возвращает 0 в своей реализации по умолчанию).

Теперь некоторые из моих контроллеров табличного представления поддерживают разбиение на страницы для отображаемых записей - когда пользователи прокручивают табличное представление до последней строки, следующая партия строк извлекается из сети. Пытаясь сделать вещи более ориентированными на протокол, я создал протокол для постраничных контроллеров:

protocol Pageable: class {
    associatedtype DataType
    var pages: [[DataType]] { get set } // Each page is an array of elements, hence the table in a table
    func loadNextPage()
}

Если контроллер Pageable, rowCount(inSection:) методы всегда выглядят так:

override func rowCount(inSection: Int) -> Int {
    return self.pages[section].count
}

Это утомительно, потому что каждый потомок BaseTableViewController, который также является Pageable, должен иметь эту точную реализацию, которая нарушает DRY.

Я не могу добавить реализацию по умолчанию в расширении протокола для Pageableпотому что контроллер уже имеет свою собственную реализацию, унаследованную от BaseTableViewController.

Я придумал решение, но мне оно не нравится: я мог бы создать PageableTableViewController (подкласс BaseTableViewController), который обеспечивает собственную переопределенную реализацию rowCount(inSection:), но это не очень ориентировано на протокол. Я также пытался переместить rowCount(inSection:) метод к протоколу, но если я сделаю все потомки BaseTableViewController, чтобы соответствовать этому протоколу с расширением протокола, расширяя Pageable реализовать метод не будет работать.

Как бы я создал механизм, где все подклассы BaseTableViewController сможет переопределить rowCount(inSection:) метод, но когда они Pageableони разделяют реализацию по умолчанию, которая (возможно) помещена в расширение протокола Pageable?

1 ответ

Вы можете достичь того, что ищете, с помощью расширений протокола. расширение будет применяться только в том случае, если объект, реализующий протокол, на самом деле является UIViewController.

protocol something {
    func method()
}
extension something where Self: UIViewController {
    func method() {
        //Default implementation
    }
}
Другие вопросы по тегам