问题
我遇到了一个问题,我有一个网络调用循环(称为 grabImage
),所有调用都将它们的回调数据附加到同一个数组,并且我正确地使用了一个调度组来不离开函数直到完成所有网络调用(直到组的进入/离开平衡)。但是,我无法控制回调编辑上述数组的顺序,并且在数据中获得随机排序。我如何确保这些回调(全部发生在单独的线程中)串行运行以保持全局数组中的顺序?
我尝试过的
我已经尝试过明显的使用串行队列,但是,因为 grabImage
函数会自行转义,我认为串行队列可能认为它在进入回调之前已经执行完毕
相关代码
//function to grab the uploaded pics of a user and store them
func fetchAllImages(_ userPicArray: [String?], _ completion: @escaping ([UIImage]) -> ()) {
var images: [UIImage] = [] //array these async calls are appending to
for photoLink in userPicArray {
//if the picture (link) exists
if photoLink != nil {
//make sure to append to the array asynchronously
appendImagesSQ.sync { //my attempt to run serially
//grab image and add it to the resImages array
self.grabImage(photoLink!) { (image) in //grabImage itself escapes
self.grabImageDispatchGroup.leave()
images.append(image)
}
}
}
}
grabImageDispatchGroup.notify(queue: grabImageSQ) {
completion(images)
}
}
最佳答案
让它们按顺序运行并不是解决这个问题的最好方法。当然,你会把它们整理好,但它会比你想要的慢得多。相反,同时启动它们,将结果存储在字典中,然后当你全部完成后,按顺序从字典中检索结果,例如
func fetchAllImages(_ userPicArray: [String?], _ completion: @escaping ([UIImage]) -> ()) {
var images: [String: UIImage] = [:] //dictionary these async calls are inserted to
let group = DispatchGroup()
let photoLinks = userPicArray.compactMap { $0 }
for photoLink in photoLinks {
group.enter()
grabImage(photoLink) { image in
images[photoLink] = image
group.leave()
}
}
group.notify(queue: .main) {
let sortedImages = photoLinks.compactMap { images[$0] }
completion(sortedImages)
}
}
顺便说一下,您的 grabImage
似乎返回了一个非可选的。但是,如果请求失败怎么办?您仍然需要调用完成处理程序。确保即使没有检索到图像,grabImage
也会调用闭包(例如,将 image 属性设为可选,无论成功或失败都调用闭包)。
此外,grabImage
是否在主队列中调用其完成处理程序?如果不是,您需要确保在串行队列上调用它,以确保线程安全,否则将需要此 images
字典的一些同步。
关于Swift:如何使异步调用(附加到数组)串行运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62251830/