Classes That Conform To Protocols
How to use type-erasers as a workaround
The other day, someone asked how to have a variable which stores a UIView
that also conforms to a protocol. In Objective-C, you would simply write UIView<HeaderViewProtocol>
. In current Swift, you can’t write something like that. This posts shows two workarounds.
First, let’s set the stage, and assume we have a HeaderViewProtocol
:
protocol HeaderViewProtocol {
func setTitle(_ string: String)
}
Until generalized existentials arrive, we’ll have to make do with a workaround. The most mechanical solution would be to write a struct which has two properties, one for the protocol and one for the UIView
. Both point to the same reference:
struct AnyHeaderView {
let view: UIView
let headerView: HeaderViewProtocol
init<T: UIView>(view: T) where T: HeaderViewProtocol {
self.view = view
self.headerView = view
}
}
let header = AnyHeaderView(view: myView)
header.headerView.setTitle("hi")
Alternatively, we could also completely get rid of the protocol, and create a HeaderView
struct which simply stores a view and a way to set the title:
struct HeaderView {
let view: UIView
let setTitle: (String) -> ()
}
var label = UILabel()
let header = HeaderView(view: label) { str in
label.text = str
}
header.setTitle("hello")
One benefit of this solution is that there are no protocols involved. More importantly, we can have multiple “implementations” of HeaderView
for a single class. This eliminates the need to subclass. I prefer this solution, as it’s really simple: just bundle up a function and a view.
(If your protocol has associated types or a Self
constraint, it will be a bit more work to write the type-eraser, see here for an explanation).