асинхронные запросы в Swift с использованием обработчика завершения и DispatchSemaphore

я пытаюсь сделать 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возвращает "истина"/"ложь"

2 ответа

Вы намерены создать синхронную функцию, которая будет блокироваться и ждать завершения асинхронного запроса?

Если это так, вы почти у цели, но вам нужно изменить семафор, чтобы он начинался с 0, а не с 1 (уменьшение с 1 до 0 не остановит выполнение, оно должно стать отрицательным), и вам нужно переместить ожидание () call вне закрытия, иначе вы не остановите возврат функции и вместо этого заблокируете завершение закрытия.

      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"))")

Ваш оператор return находится вне обработчика завершения, поэтому он будет запущен немедленно, возвращая исходное ложное значение, а не возвращая результат запроса, как вам нужно.

Вы должны удалить свойство ответа и обработать ответ внутри обработчика завершения.

Другие вопросы по тегам