Есть ли способ использовать обработчик завершения, переданный в качестве аргумента, для определения завершения длинного запроса

#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 , это делает его намного понятнее для всех, кто еще ищет 🙂