如何将 DispatchSemaphore 与 Alamofire 和 SwiftyJSON 一起使用?

How to use DispatchSemaphore with Alamofire and SwiftyJSON?

我试图在方法外使用一些 json 响应,但是当执行方法时它 return 是空数组,但在块内按预期工作,我的方法有什么办法可以return 期望值,这里是我的示例代码:

func getCarouselContent(url: String) -> [String] {
    var ids: [String] = []
    let headers = ["api_key": "My_API_KEY"]

    let semaphore = DispatchSemaphore(value: 0)
    Alamofire.request(url, headers: headers).validate().responseJSON { 
        (response) in
        semaphore.signal()
        switch response.result {
        case .success(let value):
            let json = JSON(value)
            let data = json["data"]["relationships"]["slides"]["data"]
            for child in data.array! {
                let id = child["id"].string!
                print(id) // this prints all the id
                ids.append(id)
            }
        case .failure(let error):
            print(error)
        }
    }
    semaphore.wait()
    return ids 
}

我正在使用 alamofire 和 swiftyjson 来解析 json。仅供参考,我对此并不陌生,并尝试了类似问题的回答中的解决方案,但没有奏效,非常感谢任何建议,谢谢。

将解决您原来的问题然后提供更好的解决方案:

信号量。您可能过早发出信号。当从 function/closure 返回时,安全地发出 DispatchSemaphore 信号的一个稳健的习惯用法是使用 defer 语句。例如:

Alamofire.request(url, headers: headers).validate().responseJSON {    
    (response) in {
    defer { 
        semaphore.signal() // Executed before leaving current scope.
    } 
    ...
}

这确保您 总是 触发 signal() 独立于您的退出点,避免死锁。

话虽如此,这可能远非最佳解决方案...

完成处理程序。您将 getCarouselContent 方法设计为 阻止 调用代码,直到完成网络请求,这可能需要(非常!)很长时间。 如果您打算从您的应用主线程调用此方法,这肯定会导致非常糟糕的用户体验。让我们看看 Apple says about this:

Be sure to limit the type of work you do on the main thread of your app. The main thread is where your app handles touch events and other user input. To ensure that your app is always responsive to the user, you should never use the main thread to perform long-running or potentially unbounded tasks, such as tasks that access the network. Instead, you should always move those tasks onto background threads.

一个常见的模式是将 完成块 传递给您的 getCarouselContent 方法。当 JSON 响应最终到达时,该块将传递结果。例如:

func getCarouselContent(url: String, completion: @escaping ([String]) -> Void) {
    let headers = ["api_key": "My_API_KEY"]
    Alamofire.request(url, headers: headers).validate().responseJSON { 
        (response) in
        var ids = [String]()
        switch response.result {
        case .success(let value):
            let json = JSON(value)
            let data = json["data"]["relationships"]["slides"]["data"]
            for child in data.array! {
                ids.append(child["id"].string!)
            }
        case .failure(let error):
            print(error)
        }
        completion(ids)
    }
}

并这样称呼它:

getCarouselContent(url: someUrl) {
    (ids) in 
    print("IDs received: \(ids)")
}

忘记信号量来解决方法的异步行为。学习理解异步模式并使用完成处理程序:

func getCarouselContent(url: String, completion: ([String])->())  {
       var ids = [String]()
       let headers = ["api_key": "My_API_KEY"]

        Alamofire.request(url, headers: headers).validate().responseJSON{ response in
           switch response.result {
            case .success(let value):
                let json = JSON(value)

                let data = json["data"]["relationships"]["slides"]["data"]
                for child in data.array! {
                    let id = child["id"].string!
                    print(id) // this prints all the id
                    ids.append(id)
                }
            case .failure(let error):
                print(error)
            }
            completion(ids)
        }
}

并称它为:

getCarouselContent(url: <someURL>) { identifiers in

    print(identifiers)
}