Вы немного усложняете это, используя Self
.
Все, что вам нужно сделать, это объявить инициализатор в вашем протоколе Configurable
, который принимает ваш Data
associatedtype
в качестве аргументаи имеет нестатическую функцию конфигурации:
protocol Configurable {
associatedtype Data
init(data: Data)
func configure(data: Data)
}
Обеспечить реализацию по умолчанию этого инициализатора в расширении для протокола Configurable
(для UIView
и его подклассов):
extension Configurable where Self: UIView {
init(data: Data) {
self.init(frame: CGRect.zero)
self.configure(data: data)
}
}
Наконец, добавьте соответствие протоколу через расширение для любых интересующих вас подклассов UIView
. Все, что вам нужно сделать здесь, это реализовать метод typealias
и configure
:
extension UILabel: Configurable {
typealias Data = Int
func configure(data: Data) {
text = "\(data)"
}
}
extension UIImageView: Configurable {
typealias Data = String
func configure(data: Data) {
image = UIImage(named: data)
}
}
Эта реализация имеет дополнительный бонус, который вы используете инициализатор для создания ваших представлений (стандартный шаблон Swift для создания объекта), а не статический метод:
let label = UILabel(data: 10)
let imageView = UIImageView(data: "screenshot")
Мне не совсем понятно, почему компилятору не нравится ваша версия.Я бы подумал, что подклассы UILabel
унаследуют typealias
, что означает, что у компилятора не должно быть проблем с выводом как Self
, так и Data
, но, очевидно, это еще не поддерживается.* Редактировать: @Cristik отмечает в комментариях UICollectionView
.
Эту проблему можно решить, добавив расширение протокола для Configurable
, где Self
равно UICollectionView
, используя соответствующиеинициализатор:
extension Configurable where Self: UICollectionView {
init(data: Data) {
self.init(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout())
self.configure(data: data)
}
}
Затем, при добавлении соответствия к Configurable
для UICollectionView
, мы делаем Data
typealias
a UICollectionViewLayout
:
extension UICollectionView: Configurable {
typealias Data = UICollectionViewLayout
func configure(data: Data) {
collectionViewLayout = data
}
}
Лично,Я думаю, что это разумный подход для классов, где инициализатор init(frame:)
не подходит.