Swift:如何连续进行异步调用(附加到数组)运行?
Swift: How to make async calls (appending to an array) run serially?
问题
我 运行 遇到一个问题,我有一个网络调用循环(称为 grabImage
),所有调用都将它们的回调数据附加到同一个数组,并且我正确地使用了调度组在完成所有网络调用之前不要离开函数(直到组的 enters/leaves 平衡)。但是,我无法控制回调编辑上述数组的顺序,并且在数据中获得随机排序。我如何确保这些回调全部发生在单独的线程中,运行 连续地保持全局数组中的顺序?
我试过的
我已经尝试过明显的使用串行队列,但是,因为 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 { [=10=] }
for photoLink in photoLinks {
group.enter()
grabImage(photoLink) { image in
images[photoLink] = image
group.leave()
}
}
group.notify(queue: .main) {
let sortedImages = photoLinks.compactMap { images[[=10=]] }
completion(sortedImages)
}
}
顺便说一下,您的 grabImage
returns 似乎不是可选的。但是,如果请求失败怎么办?您仍然需要调用完成处理程序。确保 grabImage
即使没有检索到图像也会调用闭包(例如,使图像 属性 可选并无论成功或失败都调用闭包)。
此外,grabImage
是否在主队列上调用其完成处理程序?如果没有,您需要确保它是在串行队列上调用的,以确保线程安全,否则将需要此 images
字典的一些同步。
问题
我 运行 遇到一个问题,我有一个网络调用循环(称为 grabImage
),所有调用都将它们的回调数据附加到同一个数组,并且我正确地使用了调度组在完成所有网络调用之前不要离开函数(直到组的 enters/leaves 平衡)。但是,我无法控制回调编辑上述数组的顺序,并且在数据中获得随机排序。我如何确保这些回调全部发生在单独的线程中,运行 连续地保持全局数组中的顺序?
我试过的
我已经尝试过明显的使用串行队列,但是,因为 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 { [=10=] }
for photoLink in photoLinks {
group.enter()
grabImage(photoLink) { image in
images[photoLink] = image
group.leave()
}
}
group.notify(queue: .main) {
let sortedImages = photoLinks.compactMap { images[[=10=]] }
completion(sortedImages)
}
}
顺便说一下,您的 grabImage
returns 似乎不是可选的。但是,如果请求失败怎么办?您仍然需要调用完成处理程序。确保 grabImage
即使没有检索到图像也会调用闭包(例如,使图像 属性 可选并无论成功或失败都调用闭包)。
此外,grabImage
是否在主队列上调用其完成处理程序?如果没有,您需要确保它是在串行队列上调用的,以确保线程安全,否则将需要此 images
字典的一些同步。