Быстрое правильное использование расширения протокола

Привет, я пытаюсь извлечь часть кода для повторного использования. Мой подход использует Protocol а также ProtocolExtension вместо общего BaseClass,

Я должен создать рев protocol а также protocol extension

protocol MovieDisplay {

    var collectionView: UICollectionView! { get set }
    var refreshControl: UIRefreshControl! { get set }

}

extension MovieDisplay where Self: UIViewController {

    var refreshControl: UIRefreshControl {
        let rc = UIRefreshControl()
        rc.backgroundColor = .clear
        rc.tintColor = .lightGray
        if #available(iOS 10.0, *) {
            collectionView.refreshControl = rc
        } else {
            // Fallback on earlier versions
            collectionView.addSubview(rc)
        }
        return rc
    }

}

В моем основном классе, который принимает протокол, я объявляю так (используя реализацию по умолчанию refreshcontrol)

class PopularMovieVC: UIViewController, MovieDisplay {

    @IBOutlet weak var collectionView: UICollectionView!

}

Проблема заключается в функции, которая включает refreshcontrol не работает. Это работает только тогда, когда я явно заявляю refreshcontrol переменная внутри основного класса и преобразовать расширение в функцию и вызвать его внутри основного класса, как показано ниже

func setupRefreshControl() {
            refreshControl.backgroundColor = .clear
            refreshControl.tintColor = .lightGray
            if #available(iOS 10.0, *) {
                collectionView.refreshControl = refreshControl
            } else {
                // Fallback on earlier versions
                collectionView.addSubview(refreshControl)
            }
}

Как правильно настроить protocol а также protocol extension для реализации по умолчанию? Спасибо

2 ответа

Ваш протокол требует получения и установки refreshControl (что возвращает UIRefreshControl!), но ваша реализация по умолчанию предоставляет только getter (и этот getter возвращает другой тип, UIRefreshControl). Ваша реализация по умолчанию также возвращает другое UIRefreshControl каждый раз, когда к нему обращаются, и изменяет collectionView каждый раз, когда к нему обращаются. Думаю, все это не то, что вы имеете в виду.

Как отмечает Вадиан, я думаю, что базовый класс - это то, что вы действительно хотите здесь, если вы хотите изменить collectionView.refreshControl автоматически. Соответствие протоколу никогда не должно вызывать неявных изменений других свойств, и в большинстве случаев это не может. Представь если PopularMovieVC были согласованы с MovieDisplay в расширении в другом модуле. Это в лучшем случае приведет к путанице.

Соответствие протокола расширяет возможности использования типа, такие как добавление новых методов. Это ничего не меняет в самом типе. Если вы хотите что-то изменить в самом типе, вам нужно что-то вроде наследования или композиции, а не соответствия протоколу.


Если вы делаете немного, я бы не стал делать это с протоколами. Я бы просто создал такие расширения:

extension UIRefreshControl {
    static func makeStandard(attachedTo collectionView: UICollectionView) -> UIRefreshControl {
        let rc = UIRefreshControl()
        rc.backgroundColor = .clear
        rc.tintColor = .lightGray
        if #available(iOS 10.0, *) {
            collectionView.refreshControl = rc
        } else {
            // Fallback on earlier versions
            collectionView.addSubview(rc)
        }
        return rc
    }
}

extension UIActivityIndicatorView {
    static func makeStandard() -> UIActivityIndicatorView {
        return UIActivityIndicatorView(style: .gray)
    }
}

Тогда ваш контроллер представления может выглядеть так:

class MyViewController: UIViewController {
    private var refreshController: UIRefreshControl!
    @IBOutlet var collectionView: UICollectionView!
    let activityIndicator = UIActivityIndicatorView.makeStandard()

    override func viewDidLoad() {
        refreshController = .makeStandard(attachedTo: collectionView)
    }
}

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

Это не работает, потому что вычисляемое свойство не вызывается неявно.

Добавление этой строки в viewDidLoad следует инициализировать элемент управления обновлением

_ = refreshControl

В этом случае я бы предпочел базовый класс

Другие вопросы по тегам