I have 2 protocols like this:
protocol Receiver {
associatedtype Input
func send(_ input: Input)
}
protocol Sender {
associatedtype Output
init<T: Receiver>(_ receiver: T) where T.Input == Output
}
To implement Sender
, I first do this:
class TestSender: Sender {
typealias Output = String
required init<T: Receiver>(_ receiver: T) where T.Input == Output {
}
}
However I need to store receiver
from init
as a class property. Since Receiver
has associated type requirements, I have to add a generic type constraint to the entire TestSender
class, like this:
class TestSender<T: Receiver>: Sender where T.Input == String
I can then declare a property in TestSender
like this:
private let receiver: T
But in the initializer, I can't assign receiver
.
required init<T: Receiver>(_ receiver: T) where T.Input == Output {
self.receiver = receiver // Cannot assign value of type 'T' to type 'T'
}
I tried changing the init method as follows:
init(_ receiver: T) {
self.receiver = receiver
}
But now, the Swift compiler says I'm not conforming to the protocol correctly. What is the correct way to do something like this?
CodePudding user response:
Solution
You can make the Receiver
have an associatedtype
on the Sender
protocol, so that a Sender
is generic over its Receiver
.
Code:
protocol Sender {
associatedtype InputReceiver: Receiver
associatedtype Output = InputReceiver.Input
init(_ receiver: InputReceiver)
}
class TestSender<T: Receiver>: Sender {
typealias Output = String
private let receiver: T
required init(_ receiver: T) {
self.receiver = receiver
}
}
Why didn't the original code work?
With your latest code, you should see the following error:
Type 'TestSender' does not conform to protocol 'Sender'
This indicates that some requirement is not being satisfied. If you click the fix-it, it shows there is a problem with the initializer. If you click the fix-it again, you get back to the problem of:
Cannot assign value of type 'T' to type 'T'
This is because you have a generic T
on TestSender
and also a generic T
on the initializer. These are different types.
However, ignoring this, the root of the problem is that: in your Sender
protocol, you only have a generic on the initializer, where as in your TestSender
class you are trying to create a generic over the class itself.
To make a protocol 'generic', you give it an associatedtype
. And since the Receiver
is the thing to make generic, that was used to create an associatedtype
.
Because we have the Receiver
generic, we can also get the Output
type in Sender
as well.
I hope that made sense, ask if you have any questions (it's quite hard to explain!)