In my project using Swift 2, I am dealing with 2 protocols, MyViewControllerProtocol
and MyViewModelProtocol
. I want all View Controllers to conform to MyViewControllerProtocol
. This protocol will require a property. The property should conform to the MyViewModel
protocol.
What I was thinking would work here would be something like this:
protocol MyViewControllerProtocol {
var viewModel: <T:MyViewModelProtocol> { get set }
}
class MyCustomViewModel: MyViewModelProtocol {
// Implementation here
}
Then for the View Controller:
class ViewController: UIViewController, MyViewControllerProtocol {
var viewModel: MyCustomViewModel {
// Getter and Setter implementations here
}
}
I am most likely thinking about this wrong. This will not compile, and I haven't yet seen this type of implementation in conjunction with a property. Is there some other pattern that could accomplish what I'm trying to do here?
If you would like to have dynamic protocol property type, there's typealias
.
protocol MyViewModel {
var title: String { get set }
}
protocol MyViewController {
typealias MyViewModelType
var viewModel: MyViewModelType { get set }
}
class BaseViewController<T: MyViewModel>: MyViewController {
typealias MyViewModelType = T
var viewModel: T
init(_ viewModel: T) {
self.viewModel = viewModel
}
}
struct CarViewModel: MyViewModel {
var title: String = "Car"
}
struct BikeViewModel: MyViewModel {
var title: String = "Bike"
}
let car = BaseViewController(CarViewModel())
let bike = BaseViewController(BikeViewModel())
If you try to use it with model not conforming to your MyViewModel
protocol, it will not work:
struct AnotherModel {
var title: String = "Another"
}
let another = BaseViewController(AnotherModel())
This has some gotchas like you can't pass your view controller via argument of MyViewController
type, because of typealias
. This is not going to work:
func something(vc: MyViewController) {
}
Why not simpler approach without typealias
. If I understood you correctly, you don't need them. Something like:
protocol MyViewModel {
var title: String { get set }
}
protocol MyViewController {
var viewModel: MyViewModel { get set }
}
class BaseViewController: MyViewController {
var viewModel: MyViewModel
init(_ viewModel: MyViewModel) {
self.viewModel = viewModel
}
}
struct CarViewModel: MyViewModel {
var title: String = "Car"
}
struct BikeViewModel: MyViewModel {
var title: String = "Bike"
}
And now you can use MyViewController
protocol as a variable type:
let bike: MyViewController = BaseViewController(BikeViewModel())
let car: MyViewController = BaseViewController(CarViewModel())
You can pass it to some function as MyViewController
:
func something(vc: MyViewController) {
}
And you can't do this as well:
struct AnotherViewModel {
var title: String = "Another"
}
let another: MyViewController = BaseViewController(AnotherViewModel())
Did I miss something? I mean, about your generics and type constraints? Do you have some use case which forces you to use them?
typealias for protocols has been deprecated and replaced with associatedtype. The above answers would now be written like:
protocol MyViewController {
associatedtype MyViewModelType
var viewModel: MyViewModelType { get set }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With