[英]Swift - Async calls in loop
希望你一切順利。 我正在努力實現以下目標:
目前,我有以下方法
self.dataAccessService.fetchRepliesByCommentId(completionHandler: { (commentReplyArray) in
for var i in 0..<commentReplyArray.count {
let commentReply = commentReplyArray[i]
let commentItem = CommentItem()
self.fetchDetailsAboutCommentReply(commentReplyObject: commentReply) { (commentItem) in
commentItem.commentObject = commentReply
dataSource.insert(commentItem, at: index + i + 1) -> APP CRASHES HERE, i is never 0 here
ips.append(IndexPath(row: index + i + 1 , section: 0))
if (i == commentReplyArray.count - 1) {
self.delegate?.didLoadReplies(dataSource: dataSource, ips: ips)
}
}
}
}, commentId: commentItem.commentObject.id)
我的 fetchDetailsAboutCommentReply function:
private func fetchDetailsAboutCommentReply(commentReplyObject:CommentReply, completionHandler:@escaping(CommentItem)->()) {
let group = DispatchGroup()
let commentItem = CommentItem()
group.enter()
self.dataAccessService.fetchUserById(completionHandler: { (userObject) in
commentItem.userObject = userObject
group.leave()
}, uid: commentReplyObject.userId)
group.enter()
self.dataAccessService.fetchDownloadURLOfProfileImage(organizerId: commentReplyObject.userId) { (contentURL) in
commentItem.userObject.contentURL = contentURL
group.leave()
}
group.notify(queue: .main) {
completionHandler(commentItem)
}
}
我的問題是如何更改我的代碼,所以循環基本上“暫停”,直到我獲取迭代的 object 的所有詳細信息,將其添加到 dataSource 數組中,然后繼續下一個?
謝謝並保持健康!
很難具體說明,因為我們沒有關於您的數據源邏輯、類型等的信息。但是,再說一次,我認為我們不想在這里討論這個問題。
所以,一些一般性的觀察:
您應該在循環中使用DispatchGroup
。 例如,
let group = DispatchGroup() for i in... { group.enter() someAsyncMethod { completion in defer { group.leave() }... } } group.notify(queue: .main) {... }
如您所見,我刪除了if (i == commentReplyArray.count - 1) {... }
test 因為您希望這些並行運行並且僅僅因為“最后一個”完成並不意味着它們我都完成了。 使用DispatchGroup
及其notify
方法可以知道它們何時完成。
我對您的dataSource.insert
調用中的+ 1
邏輯持懷疑態度(我們生活在一個從零開始的索引世界中)。 例如,您插入的第一個項目的索引應該是0
,而不是1
。 (如果你正在執行+ 1
邏輯,因為你的 tableview/collection 視圖中有一些額外的單元格,我建議不要在這個例程中糾纏偏移索引邏輯,而是讓你的“數據源”來處理。)
這可能無關緊要,因為無論如何您確實想重構此數據源,因此調用fetchDetailsAboutComent
完成處理程序的順序無關緊要。 例如,構建一個本地字典,完成后,構建排序數組並將其傳回:
// dictionary for results, so order doesn't matter var results: [Int: CommentReply] = [:] // I don't know what the type of your comment/reply is, so adjust this as needed let group = DispatchGroup() for i in 0..<20 { group.enter() someAsyncMethod { completion in defer { group.leave() }... results[i] =... } } group.notify(queue: .main) { // now build array from the dictionary let array = (0..<20).compactMap { results[i] } dataSource?.insert(array)... }
如果你真的想在結果進來時調用數據源,理論上你可以這樣做,但是你要確保你不只是插入到一個數組中,而是dataSource
object 可以在結果進來時處理它們,亂序。
您建議您希望循環“暫停”一個請求,直到前一個請求完成,我強烈建議不要使用這種模式,因為它會使過程慢得多(基本上會加劇網絡延遲效應)。 您確實需要可以讓請求並行運行的邏輯。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.