【问题标题】:Show activity indicator until all images are load successfully显示活动指示器,直到所有图像都成功加载
【发布时间】:2017-08-10 14:47:50
【问题描述】:

我有一个包含五个图像视图的 collectionView 单元格。我正在使用 javimuu 给出的以下答案在后台加载图像。 Link

它运行良好,所有图像都加载到正确的图像视图中。但这是一个非常缓慢的过程,并且图像以随机顺序加载。 在为特定单元格加载完所有图像后,我很难显示活动指示器并隐藏它,即在加载图像时继续显示指示器,并在加载所有 5 个图像时隐藏它。

请帮忙。

更新:

    func downloadImageFromLink(link:NSURL,group: dispatch_group_t, completion:(isDone: Bool) -> Void) {

    self.image = nil

    imageURL = link.absoluteString
    dispatch_group_enter(group)

    NSURLSession.sharedSession().dataTaskWithURL(link, completionHandler: {
        (data, response, error) -> Void in
        if error != nil {
            print(error)
            return
        }

        if let imageFromCache = imageCache.objectForKey(link.absoluteString) as? UIImage {

            self.image = imageFromCache
            dispatch_group_leave(group)
            return
        }
        dispatch_async(dispatch_get_main_queue(),{

            let imageToCache =  UIImage(data: data!)

            if self.imageURL == link.absoluteString {
                self.image = imageToCache
                imageCache.setObject(imageToCache!, forKey: link.absoluteString)
            }
            dispatch_group_leave(group)
        })
    }).resume()
}

func loadImagesInCell(cell: WatchFaceCell, images:NSArray ,completion:() ->Void) {
    self.startAnimating(cell.contentView)
    let group: dispatch_group_t = dispatch_group_create()
    for model in images{
        if model is WFCreatorModel {
            let wfModel: WFCreatorModel = model as! WFCreatorModel
            switch wfModel.imageType {
            case .Dial:
                cell.dialImage.downloadImageFromLink(wfModel.imageURL,group: group, completion: { (isDone) in
                })
            case .HourHand:
                cell.hourHandImage.downloadImageFromLink(wfModel.imageURL,group: group, completion: { (isDone) in
                })
            case .MinuteHand:
                cell.minuteHandImage.downloadImageFromLink(wfModel.imageURL,group: group, completion: { (isDone) in
                })
            case .SecondHand:
                cell.secondHandImage.downloadImageFromLink(wfModel.imageURL,group: group, completion: { (isDone) in
                })
            case .Notification:
                cell.notificationImage.downloadImageFromLink(wfModel.imageURL, group: group,completion: { (isDone) in
                })
            }//end of switch
        }//end of if else
    }//end of for
    dispatch_group_notify(group, dispatch_get_main_queue()) {
        self.stopAnimating(cell.contentView)
        completion()
    }
}

【问题讨论】:

  • 速度缓慢可能是由于图像太大。了解何时完成的一个快速解决方案是保留一个计数器:在调度异步之前递增它并在主队列的调度中递减它(并检查零)。
  • @danh 你能举个例子解释一下吗?

标签: ios iphone swift asynchronous uiimageview


【解决方案1】:

您将需要使用DispatchGroup,您可以在发出异步请求时进入和离开。然后,您使用.notify(queue:) 方法,该方法在组为“空”时触发。我能够找到与您正在寻找的代码非常相似的答案,因此我将其链接在这里: Wait until swift for loop with asynchronous network requests finishes executing

如果您还有其他问题,请告诉我。希望这会有所帮助!

【讨论】:

  • 感谢您的回复。我已经尝试了 dispatchGroup 并且它适合我的需要,但我仍然面临一个问题,即活动指示器会迅速出现并消失。它命中了我正在维护缓存的 dispatch_group_leave(group) 5 次,然后命中了 dispatch_group_notify 调用。但此时图像并未加载到 imageView 中。在 main_queue() 中调用它们会导致 UI 滞后,这是我最初的问题,因此所有这些代码都没有用。
  • 此时你说图像没有加载到 imageView 中是什么意思?通知功能运行时它们没有加载?
  • 我的意思是说我在从 NSURLSession 得到结果后给他们分配了一个图像,但是由于他们没有在主线程上运行,所以没有立即分配。如果我在主线程上运行它,那么 UI 就会滞后。
  • 因此您可以在 dispatch_group_notify(group, dispatch_get_main_queue()) { 中一次性将图像分配给它们的 imageViews
  • 我会试一试,让你知道。谢谢!
【解决方案2】:

您应该尝试使用像 kingfisher 这样的第三方,它拥有执行此类任务所需的所有必要方法。下面是一些示例代码,只是为了给您一些东西...

var prefetcher: ImagePrefetcher?
var imageItems: [ImageItem]? {
    didSet {
        collectionView.reloadData()
    }
}

// This code goes inside one of your methods
                      self.prefetcher = ImagePrefetcher(urls: urls, optionsInfo: nil, progressBlock: nil, completionHandler: { [weak self]
                            (skippedResources, failedResources, completedResources) -> () in
                            self?.endLoading()
                            self?.imageItems = filteredItems
                            self?.timerLabel.countFrom(15, to: 0, withDuration: 15.0)
                            self?.timerLabel.completionBlock = { self?.startGuessing() }
                        })
        self.prefetcher!.start()

【讨论】:

  • 感谢您的回复,但这并不能解决我的问题。我怎么知道对于一个特定的单元格,所有 5 个图像都已加载?您给出的示例仅适用于缓存图像,不适用于下载图像。我需要分别下载每个图像,以便我可以在正确的单元格中为正确的 imageView 设置它。
猜你喜欢
  • 1970-01-01
  • 2016-12-21
  • 2022-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多