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!)
