Быстрое правильное использование расширения протокола
Привет, я пытаюсь извлечь часть кода для повторного использования. Мой подход использует Protocol
а также Protocol
Extension
вместо общего 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
В этом случае я бы предпочел базовый класс