#swift #closures
#swift #замыкания
Вопрос:
У меня возникли проблемы с пониманием того, как использовать замыкание для обработки завершенных событий при передаче функции в качестве параметра.
Вот очень надуманный пример:
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()
Я хочу узнать, когда sendMessage
он завершен (если, например, он выполнял что-то вроде сетевого запроса), так есть ли способ иметь обработчик завершения для sendMessage
, чтобы я мог написать что-то вроде:
messenger.sendMessage {
print("I finished sending a message!")
}
Я попытался добавить подобный обработчик завершения в класс service:
func sendMessage(s: String, completion: @escaping () -> Void) {
MessageRequest(with: s) {
completion()
}
}
Но все начало становиться очень запутанным, когда я пытаюсь использовать createMessenger
метод, потому что вышеупомянутая функция имеет какой-то сумасшедший тип (String, () -> ()) -> ()
, с которым я не знаю, как обращаться. Любая помощь была бы с благодарностью принята, спасибо.
Комментарии:
1. комментарий, не имеющий прямого отношения, но мне очень сложно отслеживать все «что-то», что у вас там есть. Можете ли вы обновить свой вопрос и дать либо более описательные, либо просто другие имена, где это имеет смысл
2. Конечно, я постараюсь сделать что-нибудь более читаемое 🙂
Ответ №1:
Итак, похоже, что вам нужен произвольный тип Messenger, создатель которого сообщает ему, какое действие выполнить, и как только действие выполнено, он вызывает обработчик завершения вызывающего его.
Это помогает, если вы используете typealias
с описательными именами, чтобы отслеживать все замыкания. И если вы не возражаете, я назову это в более общем виде как 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)
}
}
Таким образом, Agent
может быть создано с помощью произвольного действия, которое принимает обработчик завершения для сигнализации о завершении:
let agent = Agent.create { completion in
print("started executing action")
DispatchQueue.main.asyncAfter(deadline: .now() 2) { completion() }
}
agent.execute { print("done") }
Теперь вы можете адаптировать его к вашему MessengerService
классу:
class MessageService {
func sendMessage(s: String) {
print(s)
}
var messenger: Agent {
Agent.create { completion in
sendMessage("This is a hardcoded message.")
completion()
}
}
}
Комментарии:
1. Большое вам спасибо за этот ответ, это отличное решение и на самом деле очень элегантное. p.s. хороший призыв переименовать его в
Agent
, это делает его намного понятнее для всех, кто еще ищет 🙂