#swift #signals #dispatchsemaphore
#swift #сигналы #диспетчерский семафор
Вопрос:
Я пытаюсь отправлять async
запросы на Swift, используя Alamofire's
completion handler
и DispatchSemaphores
. Мне нужно получить ответ, а затем вернуть его другому методу, так что в основном это мой код
func customRequest(zipCode: String) -> Bool{
var response = false
let dispatchQueueProcess = DispatchQueue.global(qos: .userInitiated)
let semaphore = DispatchSemaphore(value: 1)
dispatchQueueProcess.async {
semaphore.wait()
apiRequest(zipCode: zipCode) { apiResponse in
if apiResponse != nil {
response = apiResponse
} else {
print("Server did not Response")
}
semaphore.signal()
}
}
return response
}
Проблема в том, что запрос всегда возвращается false
, потому что не ожидает apiRequest
ответа… Есть ли у вас какие-либо идеи, как это исправить? Большое вам спасибо!
Ps. apiRequest
возвращает «true» /»false»
Ответ №1:
Вы намерены создать синхронную функцию, которая будет блокировать и ждать, пока асинхронный запрос не завершится?
Если это так, вы почти на месте, но вам нужно изменить семафор, чтобы он начинался с 0, а не с 1 (уменьшение с 1 до 0 не остановит выполнение, оно должно быть отрицательным), и вам нужно переместить вызов wait() за пределы закрытия, иначе вы не остановите функциюот возврата и вместо этого будет блокировать завершение вашего закрытия.
func customRequest(zipCode: String) -> Bool {
var response = false
let dispatchQueueProcess = DispatchQueue.global(qos: .userInitiated)
let semaphore = DispatchSemaphore(value: 0)
// Start async work on background thread, current function's thread
// execution point will then immediately move to the line
// after the closing brace
dispatchQueueProcess.async {
apiRequest(zipCode: zipCode) { apiResponse in
if let apiResponse = apiResponse {
response = apiResponse
} else {
print("Server did not Response")
}
// Tell the original function's thread that it is OK to continue
semaphore.signal()
}
}
// Immediately wait for the semaphore after starting the async work so that
// the customRequest(zipCode:) function pauses here until the semaphore is
// signalled in the closure.
semaphore.wait()
// Once the semaphore.signal() call happens in the async closure execution
// resumes, and the response variable can now be returned with the updated
// value.
return response
}
Возможно, вы обнаружите, что на самом деле не хотите создавать подобную синхронную функцию, потому что, если вы вызовете это из основной очереди, вы заморозите пользовательский интерфейс до получения ответа.
Редактировать: этот пример должен выполняться для копирования и вставки на игровой площадке
import Foundation
// template function to simulate the API call
func apiRequest(zipCode: String, response: (Bool?)->Void) {
sleep(3)
response(true)
}
func customRequest(zipCode: String) -> Bool{
var response = false
let dispatchQueueProcess = DispatchQueue.global(qos: .userInitiated)
let semaphore = DispatchSemaphore(value: 0)
dispatchQueueProcess.async {
apiRequest(zipCode: zipCode) { apiResponse in
if let apiResponse = apiResponse {
response = apiResponse
} else {
print("Server did not Response")
}
semaphore.signal()
}
}
semaphore.wait()
return response
}
print("Result: (customRequest(zipCode: "90030"))")
Комментарии:
1. это именно то, что я ищу! Позвольте мне попробовать завтра на работе, и я дам вам знать, работает ли ваше решение, надеюсь, это произойдет. Большое вам спасибо!
2. Не сработало, чувак, единственное, что произошло, это стоп-экран, так что я попробую то, что сказал Фланкер.
3. Когда вы говорите «экран замораживания», что вы имеете в виду? Вы имеете в виду, что пользовательский интерфейс блокируется при вызове этой функции? Если это так, то этого следовало бы ожидать, если ваша цель действительно состоит в том, чтобы создать блокирующую оболочку вокруг вызова. Когда я запускаю это на игровой площадке, все работает так, как описано. Обновил приведенный выше пример тем, что вы можете скопировать и вставить непосредственно на игровую площадку.
4. Я имею в виду, что процесс API не отвечал только в том случае, если я использую обработчик завершения вместо возвращаемого примера
Ответ №2:
Ваш оператор return находится за пределами обработчика завершения, поэтому он будет выполняться немедленно, возвращая его начальное значение false, а не возвращая результат запроса, как вам требуется.
Вы должны удалить свойство response и обработать ответ внутри обработчика завершения.