I'm trying to describe a delegate property with a generic protocol without making the class generic:
protocol ActionHandler: class {
associatedtype Action
func handle(_ action: Action)
}
enum SomeAction {
case dismiss
}
class Foo {
typealias Action = SomeAction
// Protocol 'ActionHandler' can only be used as a generic constraint because it has Self or associated type requirements
weak var handler: ActionHandler?
// Ideally some form of ActionHandler<Action>?
}
class Handler: ActionHandler {
func handle(_ action: SomeAction) {
switch action {
case .dismiss:
print("dismiss")
}
}
}
let handler = Handler()
Foo().handler = handler
I can instead replace the property by a closure, but I don't like this pattern as much, and I would have to do so for every method described in the protocol.
enum SomeAction {
case dismiss
}
class Foo {
typealias Action = SomeAction
var handleAction: ((Action) -> Void)?
}
class Handler {
func handle(_ action: SomeAction) {
switch action {
case .dismiss:
print("dismiss")
}
}
}
let handler = Handler()
Foo().handleAction = handler.handle(_:)
Is there a better solution?
You don't have to make
Foogeneric, but you'll need a very good reason not to. Anyway, here's one way that is built on top of your closure approach - What if we wrap those closures in a type?Now if there are more methods in
ActionHandler, you can just add it in this type, rather than adding them everywhere where you assigned toFoo.handler.Foocan just haveAnd assigning the handler looks like:
This
AnyActionHandlertype is called a "type eraser".