'Generic delegate response handlers
I've got a class currently something like this
class Client {
var responseOneDelegate: ResponseOneDelegate?
var responseTwoDelegate: ResponseTwoDelegate?
...
func onData(forMessageType messageType: MessageType, data: Data) {
switch messageType {
case .responseOne:
let response = JSONDecoder().decode(Response<ResultForResponseOne>.self, from: data)
responseOneDelegate?.received(response: response)
case .responseTwo:
let response = JSONDecoder().decode(Response<ResultForResponseTwo>.self, from: data)
responseTwoDelegate?.received(response: response)
}
}
}
protocol ResponseOneDelegate {
func received(response: Response<ResultForResponseOne>)
}
protocol ResponseTwoDelegate {
func received(response: Response<ResultForResponseTwo>)
}
With the idea that a class can be one or multiple delegates
class Handler: ResponseOneDelegate, ResponseTwoDelegate {
func received(response: Response<ResultForResponseOne>) { }
func received(response: Response<ResultForResponseTwo>) { }
}
This seems to be screaming out to be generalised as there will be quite a lot of responses in this format, but I can't quite figure out how to do it
I've tried using a generic type to make just a single delegate
protocol ResponseDelegate: AnyObject {
associatedtype T
func received(response: Response<T>)
}
It doesn't seem possible to store the delegates in Client
in [MessageType: ResponseDelegate]
so with the idea of the generic delegate I'm not sure how I'd store the references of the delegates? Maybe I'd just have to cast them before calling?
How would you generalise this?
Solution 1:[1]
Functions may be helpful here, in cases where you have a protocol with just a single function in it, and few types that implement the protocol. Here's an example of the idea:
class Client {
var handle: ((Data) -> Bool)
init(handle: @escaping ((Data) -> Bool)) {
self.handle = handle
}
func received(data: Data) {
handle(data)
}
}
let ints = { (data: Data) -> Bool in
guard let i = try? JSONDecoder().decode(Int.self, from: data) else {
return false
}
print("handle \(i)")
return true // if handled
}
let strings = { (data: Data) -> Bool in
guard let str = try? JSONDecoder().decode(String.self, from: data) else {
return false
}
// handle Strings
print("handle \(str)")
return true
}
let intOrString = { (data: Data) -> Bool in
ints(data) ||
strings(data)
}
func handleMany(handlers: ((Data) -> Bool)...) -> (Data) -> Bool {
return { data in
for handle in handlers {
if handle(data) {
return true
}
}
return false
}
}
let intsOrStrings = handleMany(handlers: ints, strings)
let aOrBClient = Client(handle: intsOrStrings)
let aClient = Client(handle: ints)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Shadowrun |