[英]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.