1

I'm trying to make a complex class hierarchy conform to protocols, which help me to reuse code fragments. To that end, I face the following issue: class A has a property b, that is an instance of class B. B does conform to ProtocolB. Now I want to define a protocol ProtocolA, such that A does conform to ProtocolA and that ProtocolA specifies b of type ProtocolB.

This is what I came up with:

class A {
    var b: B?
}

class B {}

protocol ProtocolA {
    var b: ProtocolB? { get }
}

protocol ProtocolB {}

extension B: ProtocolB {}
extension A: ProtocolA {}

Unfortunately, XCode shows the error:

Type 'A' does not conform to protocol 'ProtocolA'.

It is important to mention, that I can not directly define classes A and B like:

class A: ProtocolA {
    var b: ProtocolB?
}

class B: ProtocolB {}

since the classes A and B are predefined by a library.

Asad Ali Choudhry
  • 4,985
  • 4
  • 31
  • 36
j4rv1s
  • 23
  • 6
  • Do you need to use `ProtocolA` as the type of a variable or a method parameter? If so, you can't do this in a type-safe way. – Sweeper Jun 25 '19 at 11:59

2 Answers2

1

You can do this with associated types.

Declare an associated type in ProtocolA:

protocol ProtocolA {
    associatedtype BType: ProtocolB
    var b: BType? { get } // Note the change in the type of b
}

This is saying that b is an optional of some type that conforms to ProtocolB. What type exactly? That depends on the conformers of ProtocolA.

In A's extension, you specify what BType is:

extension A: ProtocolA {
    typealias BType = B
}

And you're done!

As a result of this, you won't be able to use ProtocolA as the type of a variable:

var protocolA: ProtocolA? // error

Because you don't know what b's type is.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Thank you a lot! One question regarding the use of `ProtocolA` as method parameter: Would this be correct: `func foo(a: T) {}` – j4rv1s Jun 25 '19 at 12:17
  • Yes you can use it as a type constraint, just not as a type. – matt Jun 25 '19 at 12:22
0

You can use associatedtype for this:

class A {
    var b: B?
}

class B {}

protocol ProtocolA {
    associatedtype PB: ProtocolB
    var b: PB? { get }
}

protocol ProtocolB {}

extension B: ProtocolB {}
extension A: ProtocolA {}
Fabio Felici
  • 2,841
  • 15
  • 21