简体   繁体   中英

Alamofire completionHandler of responseJSON is not called

I have the following code to fetch the replies to a list of comments. (1 comment has many replies)

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

The complete handler of API.listReply request is never called. dispatch_group_enter(group) is called once, and dispatch_group_leave(group) is never called. The code gets stuck at dispatch_group_wait . What's strange is, even the UI is stuck, which is strange because the entire function is async.

I have encounter similar problem:

on Main UI thread, call:

dispatch_semaphore_wait(loginDoneSemaphore, DISPATCH_TIME_FOREVER)

and call http using Alamofire, internal also use your httpRequest.responseJSON

-> finally found code inside responseJSON completion handler never called

-> cause find code after DISPATCH_TIME_FOREVER never called

-> finally find root cause is: Alamofire's responseJSON, default, if you not pass in the thread/queue, will run on Main UI thread

-> before call Alamofire, have inside Main UI thread, to use DISPATCH_TIME_FOREVER lock UI thread

-> so following Alamofire's responseJSON, which run also on Main UI thread, will never called

-> my solution is: designate Alamofire do http response on another thread:

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]
})

this maybe useful for you to refer.

-> maybe you can use my method: set another thread for Alamofire's responseJSON, to solve your problem.

I'm not familiar with Alamofire internals, but it seems likely that it fulfills all your response completionBlocks on the same serial queue. Your dispatch_group_wait is blocking other responses from finishing and calling their dispatch_group_leave s.

You can solve this problem by using dispatch_group_notify instead of dispatch_group_wait , so rather than blocking the thread it will simply submit the block to a queue when necessary.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM