Reputation: 2856
I'm having trouble understanding how to use a closure to handle completed events when passing in a function as a parameter.
Here's a very contrived example:
class MessageService {
func sendMessage(s: String) {
print(s)
}
var messenger: Messenger {
createMessenger(completion: sendMessage(s:))
}
}
func createMessenger(completion: @escaping (String) -> Void) -> Messenger {
return Messenger { completion("This is a hardcoded message.") }
}
struct Messenger {
let sendMessage: () -> Void
init(sendMessage: @escaping () -> Void) {
self.sendMessage = sendMessage
}
}
let service = MessageService()
let messenger = service.messenger
messenger.sendMessage()
I want to find out when sendMessage
is finished (if for example it was performing something like a network request), so is there a way of having a completion handler for sendMessage
so that I could write something along the lines of:
messenger.sendMessage {
print("I finished sending a message!")
}
I've tried adding a completion handler like this in the service class:
func sendMessage(s: String, completion: @escaping () -> Void) {
MessageRequest(with: s) {
completion()
}
}
But things started getting very confusing when I'm trying to use the createMessenger
method, because the above function has some crazy type of (String, () -> ()) -> ()
which I don't know how to handle. Any help would be greatly appreciated, thanks.
Upvotes: 0
Views: 236
Reputation: 49590
So, it sounds like what you want is an arbitrary Messenger type, whose creator tell it what action to do, and once the action is done, it invokes its caller's completion handler.
It helps if you use typealias
with descriptive names to keep track of all the closures. And if you don't mind, I'll name it more generically as Agent
:
struct Agent {
typealias Completion = () -> Void
typealias Action = (Completion) -> Void
private let action: Action
static func create(action: @escaping Action) -> Agent {
Agent(action: action)
}
func execute(_ completion: @escaping Completion) {
action(completion)
}
}
So, Agent
can be created with an arbitrary action that accepts a completion handler to signal when it's done:
let agent = Agent.create { completion in
print("started executing action")
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { completion() }
}
agent.execute { print("done") }
Now, you can adapt it to your MessengerService
class:
class MessageService {
func sendMessage(s: String) {
print(s)
}
var messenger: Agent {
Agent.create { completion in
sendMessage("This is a hardcoded message.")
completion()
}
}
}
Upvotes: 1