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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With