2015-01-06 5 views
2

Вот сценарий. У меня есть несколько разных представлений, которые я хочу показать, в зависимости от объекта модели, который я показываю пользователю. Поэтому я создал протокол, в котором можно представить любое представление, которое его реализует.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), когда вы ссылаетесь на них в своем контроллере просмотра.

+0

Каково сообщение об ошибке из компилятора? – Aggressor

+0

Ваш товарный вид не распространяется UIView – Aggressor

+0

Ваш образец кода должен измениться на 'var itemView: SpecificItemView?' – Aggressor

ответ

-1

ItemView не распространяется UIView, но ваш SpecificItemView. Естественно, на вашем ItemView нет removeFromSuperView.

В вашем ViewController вы объявляете объект ItemView типа, а не SpecificItemView

Изменить MyViewController код:

var itemView:SpecificItemView? 
+0

Это будет работать, за исключением того, что целью здесь является наличие нескольких различных классов «SpecificItemView», например. 'SongItemView' и' AlbumItemView' –

+0

Можете ли вы рассказать мне, почему ItemView не расширяет UIView в первую очередь? – Aggressor

+0

В настоящее время я не вижу веской причины (но, может быть, и есть!), Но, предполагая, что вы не можете просто создать свою собственную функцию remove(), и когда вы создаете экземпляр подкласса, вы назначаете эту переменную-член и вызываете удаление на этом ? Итак, ваш ItemView имеет общую переменную вида View, которая присваивается при вызове setupItem? – Aggressor

1

Как вы обнаружить, что нет никакого способа определить как класс и протокол для объекта.

Самый простой способ исправить проблему состоит в том, чтобы добавить removeFromSuperview (и любые другие методы UIView, необходимые для обеспечения), в ваш протокол.

0

Возможно, следующее (в Swift 4) выполнит трюк?

class MyViewController: UIViewController { 
    typealias T = UIView & ItemView 

    var itemView: T? 
} 
Смежные вопросы