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

Posted

技术标签:

【中文标题】如何将 DispatchSemaphore 与 Alamofire 和 SwiftyJSON 一起使用?【英文标题】:How to use DispatchSemaphore with Alamofire and SwiftyJSON? 【发布时间】:2017-05-28 19:53:23 【问题描述】:

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

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。仅供参考,我对此很陌生,并尝试了类似问题的回复中的解决方案,但没有奏效,非常感谢任何建议,谢谢。

【问题讨论】:

【参考方案1】:

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

信号量。您可能过早地发出信号。当从函数/闭包返回时,安全地发出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:

请务必限制您在应用主线程上执行的工作类型。主线程是您的应用处理触摸事件和其他用户输入的地方。为确保您的应用始终响应用户,您不应使用主线程来执行长时间运行或可能无限制的任务,例如访问网络的任务。相反,您应该始终将这些任务移至后台线程。

一个常见的模式是将一个完成块传递给你的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)")

【讨论】:

【参考方案2】:

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

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)

【讨论】:

以上是关于如何将 DispatchSemaphore 与 Alamofire 和 SwiftyJSON 一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

Swift DispatchSemaphore 正在冻结应用程序

如何正确使用信号灯同步 Alamofire 请求 Swift4 的主线程?

Swift Async - Task.detached 在哪个线程上运行?

如何将嵌套字典列表与它们的值中的公共键相加? [复制]

如何将 libcurl 与 dev c++ 静态链接?

如何将数组的每个元素与同一数组的其他元素相加?