未调用 responseJSON 的 Alamofire completionHandler

Posted

技术标签:

【中文标题】未调用 responseJSON 的 Alamofire completionHandler【英文标题】:Alamofire completionHandler of responseJSON is not called 【发布时间】:2016-01-09 07:44:58 【问题描述】:

我有以下代码来获取对 cme​​ts 列表的回复。 (1 条评论有很多回复)

static func fetchCommentsAndTheirReplies(articleId: String, failure: (()->Void)?, success: (comments: [[String: AnyObject]], replies: [[[String: AnyObject]]], userIds: Set<String>)->Void) 
    var retComments = [[String: AnyObject]]()
    var retReplies = [[[String: AnyObject]]]()
    var retUserIds = Set<String>()

    Alamofire.request(.GET, API.listComment, parameters: [API.articleId: articleId]).responseJSON 
        response in
        guard let comments = response.result.value as? [[String: AnyObject]] else 
            failure?()
            return
        
        print(comments)
        retComments = comments

        let group = dispatch_group_create()

        for (commentIndex, comment) in comments.enumerate() 
            guard let id = comment["_id"] as? String else continue

            let relevantUserIds = parseRelaventUserIdsFromEntity(comment)
            for userId in relevantUserIds 
                retUserIds.insert(userId)
            

            retReplies.append([[String: AnyObject]]())

            dispatch_group_enter(group)
            Alamofire.request(.GET, API.listReply, parameters: [API.commentId: id]).responseJSON 
                response in
                if let replies = response.result.value as? [[String: AnyObject]] 
                    for (_, reply) in replies.enumerate() 

                        let relevantUserIds = parseRelaventUserIdsFromEntity(reply)
                        for userId in relevantUserIds 
                            retUserIds.insert(userId)
                        
                    
                    //TODO: need to capture commentIndex?
                    retReplies[commentIndex] = replies
                
                dispatch_group_leave(group)
            


        

        dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
        success(comments: retComments, replies: retReplies, userIds: retUserIds)
    

API.listReply 请求的完整处理程序永远不会被调用。 dispatch_group_enter(group) 被调用一次,并且 dispatch_group_leave(group) 永远不会被调用。代码卡在dispatch_group_wait。 奇怪的是,连UI都卡住了,这很奇怪,因为整个功能都是异步的。

【问题讨论】:

Alamofire 是否使用内部串行队列?您可能会无意中将其陷入僵局。你应该在它被冻结时暂停执行,看看它在哪里等待。 总是停在这一行:dispatch_group_wait(group, DISPATCH_TIME_FOREVER) 但是还发生了什么?该组中的某些块必须等待运行。 我认为这是死锁问题。但不知道怎么做? 尝试使用 dispatch_group_notify 而不是 _wait。 【参考方案1】:

我也遇到过类似的问题:

在主 UI 线程上,调用:

dispatch_semaphore_wait(loginDoneSemaphore, DISPATCH_TIME_FOREVER)

并使用 Alamofire 调用 http,内部也使用您的 httpRequest.responseJSON

-> 终于在 responseJSON 完成处理程序中找到了从未调用过的代码

-> 导致在 DISPATCH_TIME_FOREVER 之后查找代码从未被调用

-> 最终找到根本原因是:Alamofire的responseJSON,默认,如果不传入thread/queue,会在Main UI thread上运行

-> 在调用 Alamofire 之前,在 Main UI 线程中,使用 DISPATCH_TIME_FOREVER 锁定 UI 线程

-> 所以在主 UI 线程上运行的 Alamofire 的 responseJSON 将永远不会被调用

-> 我的解决方案是:指定 Alamofire 在另一个线程上做 http 响应:

let BackgroundThread:dispatch_queue_t = dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)

func dispatchBackground_async(thingsTodo:()->()) 
    dispatch_async(BackgroundThread, thingsTodo)


dispatchBackground_async(
    httpRequest.responseJSON(queue: BackgroundThread, completionHandler:  response in
        gLog.debug("request=\(response.request), response=\(response.response), statusCode=\(response.response?.statusCode), result=\(response.result)")
        // [Debug] [com.apple.root.background-qos] [CrifanLibHttp.swift:21]
)

这可能对你有用。

->也许你可以用我的方法:为Alamofire的responseJSON设置另一个线程,来解决你的问题。

【讨论】:

【参考方案2】:

我不熟悉 Alamofire 的内部结构,但它似乎很可能在同一个串行队列上完成所有响应完成块。您的dispatch_group_wait 阻止其他回复完成并致电他们的dispatch_group_leaves。

您可以通过使用dispatch_group_notify 而不是dispatch_group_wait 来解决此问题,因此它不会阻塞线程,而是在必要时将块提交到队列。

【讨论】:

以上是关于未调用 responseJSON 的 Alamofire completionHandler的主要内容,如果未能解决你的问题,请参考以下文章

SwiftyJSON Alamofire 无法使用类型为 ((_,_,_,_))->_) 的参数列表调用 responseJSON

ReactJs 和 D3.js :未捕获(承诺中) SyntaxError: Unexpected token < in JSON at position 0 at responseJson

AlamoFire responseJSON 十进制精度

Alamofire 无法在 .responseJSON 中创建 throw

AlamoFire 与 Swift 1.2:“responseJSON”的模糊使用

Swift 2 - 如何从 Alamofire.responseJSON 获取数据