5

I try to set up various protocols that work hand in hand. Unfortunately I cannot make them work the way I want. Looking at the following code, I think my goal is obvious: I want to require a class that conforms to a protocol X. If it conforms to protocol Y instead but protocol Y inherits from protocol X, it should be accepted as a conforming class too. Instead I receive the following compile error

Unable to infer associated type 'VC' for protocol 'ViewModelType'

Inferred type 'ExampleViewControllerType' (by matching requirement 'viewController') is invalid: does not conform to 'ViewType'

Current setup:

protocol ViewModelType: class {
    associatedtype VC: ViewType
    weak var viewController: VC! { get set }
}

class ExampleViewModel: ViewModelType {
    weak var viewController: ExampleViewControllerType!
}

protocol ViewType: class { }    
protocol ExampleViewControllerType: ViewType { }

class ExampleViewController: UIViewController, ExampleViewControllerType { 

}
alexeis
  • 2,152
  • 4
  • 23
  • 30
  • Possible duplicate of [Unable to use protocol as associatedtype in another protocol in Swift](http://stackoverflow.com/questions/37360114/unable-to-use-protocol-as-associatedtype-in-another-protocol-in-swift). Protocols don't conform to themselves, so you cannot use `ExampleViewControllerType` as a type that conforms to `ViewType`. – Hamish Oct 14 '16 at 13:14

2 Answers2

2

I can see what you are getting at with the 'transitive' protocols, however your error is caused by your associatedtype declaration of VC as seen in the error.

Unable to infer associated type 'VC' for protocol 'ViewModelType'

I think the compiler is having difficulty here maybe because its an innapropriate use of the associatedtype declaration.

An associatedtype can be thought of as a placeholder for an unknown type.

By defining VC as an associatedtype you are letting any class that inherits ViewModelType decide what type VC should be.

In ExampleViewModel class you do this by setting the type using typealias in the conforming class.

Your viewController can then be an ExampleViewControllerType without causing the 'inferred' error

protocol ViewModelType: class {
    associatedtype VC
    var viewController: VC! { get set }
}

class ExampleViewModel: ViewModelType {
    typealias VC = ExampleViewControllerType
    weak var viewController: ExampleViewControllerType!
}

protocol ViewType: class { }
protocol ExampleViewControllerType: ViewType { }

class ExampleViewController: UIViewController, ExampleViewControllerType {

}
Danoram
  • 8,132
  • 12
  • 51
  • 71
  • I also removed the weak var declaration of `viewController` in `ViewModelType` protocol as weak vars don't seem to be allowed in class and class-bound protocol types. – Danoram Oct 14 '16 at 10:26
  • In your example exampleViewModel.viewController doesn't have to conform to protocol ViewType but this is what I like to get. – alexeis Oct 14 '16 at 11:05
  • 1
    Ahah! I knew I didn't answer your question properly! I tunnel visioned on the error itself but now I understand what you mean. I think Sahil's answer is correct and my answer code just illustrates his point. – Danoram Oct 14 '16 at 11:42
1

No!! it can't be conforming class (If it conforms to protocol Y instead but protocol Y inherits from protocol X, it should be accepted as a conforming class too). A protocol can inherit one or more other protocols and can add further requirements on top of the requirements it inherits. The syntax for protocol inheritance is similar to the syntax for class inheritance. you cannot extend a protocol to conform to another protocol. only a class satisfy all of the requirements enforced by protocol. you could extend the protocol to provide default implementations.

extension Y {
  // default implementations 
}

for more Protocol Inheritance

Sahil
  • 9,096
  • 3
  • 25
  • 29
  • This is actually not too useful in my scenario, to extend my protocol X - I just want to enforce a general ViewType-class while using more specific protocols (which themselves conform to that ViewType-class) in each scenario. Anyway, I think I realized (again) it is just not possible unless I put the associatedtype in the class' definition like so `ExampleViewModel` – alexeis Oct 14 '16 at 12:02