Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
977 views
in Technique[技术] by (71.8m points)

signals - async requests on Swift using completion handler and DispatchSemaphore

I'm trying to make async requests on Swift using Alamofire's completion handler and DispatchSemaphores . I need to get a response and then return it to another method, so basically this is my code

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
}

The problem is that request always returns false because is not waiting until apiRequest responds... Do you have any idea to fix this? Thank you so much!

Ps. apiRequest returns "true"/"false"


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Is your intention here to create a synchronous function that will block and wait until the async request completes?

If so, you're almost there but you need to change the Semaphore to start with 0 rather than 1 (decrementing from 1 to 0 won't stop execution, it needs to go negative), and you need to move the wait() call outside the closure, otherwise you aren't stopping the function from returning and instead would be blocking your closure from ever completing.

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
}

You might find that you don't actually want to make a synchronous function like this, because if you call this from the main queue you will freeze the UI until the response is received.

Edit: This example should copy-paste run in a Playground

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...