我有一个运行循环的函数,为该循环中的每个项目触发另一个函数,但似乎运行该函数的次数不及数组中存在项目的次数。
这是我的职能。
func startLoop(completion: @escaping (_ finished: Bool) -> ()) {
print("Tony items amount is \(tempImgUrls.count)")
for item in tempImgUrls {
dispatchGroup.enter()
print("Tony begin loop")
let img = item["imgUrl"]
let name = item["name"]
downloadImages(img: img!, name: name!, completion: { (complete) in
print("Tony mid loop")
self.dispatchGroup.leave()
})
}
dispatchGroup.notify(queue: DispatchQueue.main) {
print("Tony end loop")
completion(true)
}
}
func downloadImages(img: String, name: String, completion: @escaping (_ finished: Bool) -> ()) {
imageShown.sd_setImage(with: URL(string: img), completed: { (image, error, cacheType, imageUrl) in
let personImg = image!
let personId = name
let post = Person(personImage: personImg, personId: personId)
self.finalImgUrls.append(post)
completion(true)
print("Tony array is with images person is \(self.finalImgUrls)")
print("Tony items 2 amount is \(self.finalImgUrls.count)")
})
}
}
这是在consol中打印的内容,因为您可以看到它先打印循环开始,然后在1次中旬和1次结束时打印循环,并在末尾附加一项,而不是像馈入的那样附加4项。 >
托尼物品数量为4
Tony开始循环
Tony开始循环
Tony开始循环
Tony开始循环
托尼中环
Tony数组与图像人是[AppName.Person]
Tony项目2的金额为1
答案 0 :(得分:0)
您所拥有的代码正在运行。问题似乎是sd_setImage
仅传递一次结果。
如何测试
如果您按以下方式使用sd_setImage
的测试实现,那么您将获得预期的结果:
class SomeClass {
func sd_setImage(with url: URL?, completed: @escaping (UIImage?, Error?, String, URL) -> Void) {
let random = Double(arc4random()) / Double(UINT32_MAX)
DispatchQueue.main.asyncAfter(deadline: .now() + random, execute: {
completed(UIImage(), nil, "a", url!)
})
}
}
答案 1 :(得分:0)
当您使用UIImageView
异步图像检索扩展时,它们在为同一图像视图请求另一个图像时总是取消对该图像视图的先前请求。 (这通常是设计使然,因为它避免了对图像的请求被不再需要相同图像视图的先前图像的请求所积压,例如可以重用的表格视图单元格中的图像视图。) / p>
问题在于,如果取消了图像检索,SDWebImage的UIImageView
扩展名不会调用其完成处理程序。这是API设计的缺陷,恕我直言,因为异步方法应始终调用其完成处理程序(如果请求被取消,则使用“取消的”错误代码)。但是由于SDWebImage不执行此操作,因此取消了循环的初始请求,而不是后续请求,因此,永远不会调用您对早期迭代的leave
调用。仅供参考,其他图像库(例如KingFisher)也不受此设计缺陷的影响(尽管它有其自身的问题)。
但这引出了您的意图是什么的问题。例如,如果您要连续查看图像序列,那么您不应该在完成前一个图像检索之前启动下一个图像检索(例如,在前一个图像的完成处理程序中启动下一个图像检索)。或者,也许您应该自己检索图像(而不使用取消先前请求的UIImageView
扩展名)并在那里进行UI的定时更新。但是您几乎可以肯定不希望针对同一图像视图启动多个并发图像更新。