使 Completionhandler 在 For 循环中工作以获取图像
Posted
技术标签:
【中文标题】使 Completionhandler 在 For 循环中工作以获取图像【英文标题】:Make Completionhandler Work in For-Loop for Image Fetching 【发布时间】:2019-05-03 20:14:39 【问题描述】:我正在从 Firebase 获取用户图片。一个用户最多可以在数据库中上传 6 张图像。我想以正确的顺序(0-6)将图像下载到 CollectionView 中。
当我尝试使用 CompletionHandler 时,它无法按我的意愿工作。 CollectionView 的重新加载在获取图像之前很久就完成了,没有显示图像,因为图像是在调用 reloadData 之后放入数组中的。
不胜感激有关此问题的帮助。
这是我的代码:
override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated)
downloadAndReload()
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
return arrayImages.count
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "swipeCell", for: indexPath as IndexPath) as! ProfileCardCollectionViewCell
let image = self.arrayImages[indexPath.item]
cell.swipeProfileImage.image = image
print("lägger ut cell")
return cell
func downloadAndReload()
cachedImage(completion: message in
print(message)
self.swipeCollectionView.reloadData()
)
func cachedImage(completion: @escaping (_ message: String) -> Void)
if let uid = Auth.auth().currentUser?.uid
for i in 0...6
let url = URL(string: uid+String(i))
SDWebImageManager.shared.loadImage(with: url, options: .refreshCached, progress: .none ,completed: (image, data, error, _, _, _) in
if let error = error
print("Couldn't download image")
self.downloadImage(i: i, completion: _ in
)
else
print("Could download image")
self.arrayImages.append(image!)
)
completion("DONE")
func downloadImage(i: Int, completion: @escaping (_ fetchWorked: String) -> Void)
print("Downloading Image")
let g = DispatchGroup()
g.enter()
if let uid = Auth.auth().currentUser?.uid
let imagesStorageRef = Storage.storage().reference().child("profilepic/").child(uid+String(i))
imagesStorageRef.downloadURL url, error in
guard let url = url else return
SDWebImageManager.shared.loadImage(with: url, options: .refreshCached, progress: .none ,completed: (image, data, error, _, _, _) in
if let error = error
else
self.arrayImages.append(image!)
)
g.leave()
g.notify(queue: .main, execute:
completion("Done")
)
【问题讨论】:
【参考方案1】:问题是你有嵌套的闭包,所以当你调用时:
SDWebImageManager.shared.loadImage(with: url, options: .refreshCached, progress: .none ,completed: (image, data, error, _, _, _) in
if let error = error
print("Couldn't download image")
self.downloadImage(i: i, completion: _ in
)
else
print("Could download image")
self.arrayImages.append(image!)
)
其中的所有内容只有在“loadImage”完成时才会被调用,因此你的“for”将调用“SDWebImageManager.shared.loadImage”6次,然后调用“completion(“Done”)”。
因此您的代码将在处理完图像之前调用“completion("Done")”,因此在没有图像或可能有图像时重新加载数据。
在调用 reloadData() 之前,您需要等待获取完成,这取决于您的需要,但您可以根据需要获取图像,当您要将图像设置为单元格内容时,调用获取图像(首先从缓存或下载,如果不可用)然后只更新它们的显示位置。 这样,您的应用程序将在屏幕上更加动态地显示,同时设置占位符图像。
【讨论】:
谢谢,问题是 CollectionView 需要知道 arrayImages.count 有多大。我只希望上传的图像显示在单元格中。这就是为什么我想在重新加载之前先下载所有图像。 但是在您的代码中,它被硬编码为始终为 6,如果您知道它始终为 6,则它是一个固定值。请记住 Facebook 和 Instagram 的情况,它们不一定会显示所有图像,它们会按需加载,然后在加载图像时更新大小(单元格数量)。如果您想先下载它们,那么最好在呈现视图之前调用该函数,但这取决于您的应用程序的结构(以上是关于使 Completionhandler 在 For 循环中工作以获取图像的主要内容,如果未能解决你的问题,请参考以下文章
在 Alamofire Swift 2.2 中使用 completionHandler
嵌入函数返回值后在函数中调用completionHandler?迅速
GMSGeoCoder reverseGeocodeCoordinate:completionHandler:在后台线程上
如何在swift中使用带有completionHandler的UIImageView load()函数