Swift 2 protocol - common type property?

In my project using Swift 2, I am dealing with 2 protocols, MyViewControllerProtocol and MyViewModelProtocol . I want all View controllers to match MyViewControllerProtocol . This protocol requires a property. The property must conform to the MyViewModel protocol.

What I was thinking would work here:

 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 most likely think it wrong. This will not compile, and I have not yet seen this type of implementation combined with a property. Is there another model that could accomplish what I'm trying to do here?

+4
source share
3 answers

If you want to have a property type of a dynamic protocol, 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 a model that does not match your MyViewModel protocol, this will not work:

 struct AnotherModel { var title: String = "Another" } let another = BaseViewController(AnotherModel()) 

This has some gotchas since you cannot pass your view controller with an argument of type MyViewController because of typealias . This will not work:

 func something(vc: MyViewController) { } 

Why not simplify the approach without typealias . If I understand you correctly, you do not need them. Sort of:

 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 the 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 cannot do this:

 struct AnotherViewModel { var title: String = "Another" } let another: MyViewController = BaseViewController(AnotherViewModel()) 

Did I miss something? I mean, about your generics and type restrictions? Do you have any precedent that forces you to use them?

+4
source

typealias for protocols is deprecated and replaced with the associated type. The above answers will now be written like this:

 protocol MyViewController { associatedtype MyViewModelType var viewModel: MyViewModelType { get set } } 
+3
source

Protocols in Swift do not have common angle brackets. To use general behavior, you must use typealias :

 protocol MyViewControllerProtocol { typealias T: MyViewModelProtocol var viewModel: T { get set } } 
+1
source

All Articles