Вот сценарий. У меня есть несколько разных представлений, которые я хочу показать, в зависимости от объекта модели, который я показываю пользователю. Поэтому я создал протокол, в котором можно представить любое представление, которое его реализует.Swift: свойство, являющееся подклассом UIView, реализующим протокол
class MyItem { /* some model properties */ }
protocol ItemView: class {
// some protocol methods (e.g. updateWithItem(), etc)
func setupItem(item: MyItem)
}
class SpecificItemView: UIView, ItemView { /* there will be multiple classes like this */
func setupItem(item: MyItem) {
// do item setup
}
}
class AnotherItemView: UIView, ItemView {
func setupItem(item: MyItem) {
// do DIFFERENT item setup
}
}
Тогда, когда я иду, чтобы использовать их в контроллере представления, я был дан один из моих классов ItemView:
class MyViewController: UIViewController {
var itemView: ItemView? // could be a SpecificItemView or AnotherItemView
override func viewDidLoad() {
itemView?.setupItem(MyItem())
itemView?.removeFromSuperview() /* this line won't compile */
}
}
Все работает за исключением того, что последней строке, где я пытаюсь вызвать до UIView
(removeFromSuperview
). Не удивительно, что ItemView
не имеет отношения к UIView
.
В Objective C Я хотел бы решить эту проблему, указав мой itemView Ивар так:
@property (nonatomic, strong) UIView<ItemView> *itemView;
Но я не могу найти подобный синтаксис для Swift. Я подозреваю, что использовать этот шаблон в Swift невозможно. Как достичь моей общей цели взаимозаменяемых классов UIView с помощью Swift-friendly?
Один Hacky решение, которое я нашел до сих пор, чтобы добавить любые UIView
методы, которые я называю (например, removeFromSuperview
) к моему ItemView
протоколу.
Другое предложение, которое я получил, а не на SO, из Maurice Kelly, должен был сделать UIView
подкласс, реализации протокола ItemView
, что оба SpecificItemView
и AnotherItemView
могут спуститься с. Вы можете видеть это implemented in this gist. Хотя это решает проблему инкапсуляции класса и протокола в одном типе (например, var itemView: ItemViewParentClass
), это в основном делает протокол бессмысленным, поскольку теперь вы применяете все методы протокола в своем родительском классе и переопределяете их в своих подклассах. Единственный самый большой недостаток этих решений заключается в том, что вы должны бросать экземпляры подклассов (SpecificItemView
) в новый гипотетический родительский класс (ItemViewParentClass
), когда вы ссылаетесь на них в своем контроллере просмотра.
Каково сообщение об ошибке из компилятора? – Aggressor
Ваш товарный вид не распространяется UIView – Aggressor
Ваш образец кода должен измениться на 'var itemView: SpecificItemView?' – Aggressor