UITableView 加载图像缓慢



TableView从解析API获取图像。但是,在 tableView 中滚动时,加载图像时会出现延迟。

有没有减少滞后的有效方法?在用户滚动到单元格之前(甚至之后(加载图像的某种方法?我不太熟悉处理异步调用。

获取图像功能

func fetchImage(restaurantArray: PFObject!, completionHandler: ImageCompletionHandler!){
    var imageReference = restaurantArray["PhotoUploaded"] as PFFile
    imageReference.getDataInBackgroundWithBlock{
        (data, error) -> Void in
        if (error != nil){
            completionHandler(image: nil, error: error)
        }else{
            let image = UIImage(data: data)
            completionHandler(image: image, error: nil)
        }
    }
}

表视图单元格

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("RestaurantCell", forIndexPath: indexPath) as FeedCell
    cell.nameLabel.text = restaurantNames[indexPath.row]
    // check if image is empty
    if foodPhotoObjects.isEmpty {
    } else {
        self.fetchImage(self.foodPhotoObjects[indexPath.row] as? PFObject, completionHandler: {
            (image, error) -> () in
            if image != nil {
                cell.mainRestaurantImageView.image = image
                cell.mainRestaurantImageView.contentMode = .ScaleAspectFill
                cell.mainRestaurantImageView.clipsToBounds = true
            }else{
                //alert user: no image or put placeholder image
            }
        })
    }
    return cell
}

您可以使用PFImageView免费获得此功能,编写更少的代码来达到所需的效果。只需在设置 file 属性后调用loadInBackground:即可。

https://parse.com/docs/ios/api/Classes/PFImageView.html

至于 UI 滞后,在仪器中配置文件以确定什么如此昂贵以至于导致明显的明显滞后。

几个想法:

  1. 您应该确认此完成块是否在主线程上运行(检查NSThread.isMainThread(,如果没有,请确保将图像视图的更新调度回主线程,例如 dispatch_async(dispatch_get_main_queue()) { ... } .尝试从后台线程执行 UIKit 控件的更新最终可能会导致行为不一致,因此请确保仅从主线程更新 UI。

  2. 应考虑用户在表视图中快速向下滚动和向上滚动的含义。您的代码将导致重新获取以前检索到的图像。

    有时,底层NSURLCache会优雅地处理此问题,为您缓存图像。 在其他情况下,它不会。 (可悲的是,网络请求的缓存是由一些相当不透明的标准决定的,并且根据服务器实现,您可能对此没有太多控制权。

    您可能希望确认您的行为,并实现您自己的缓存(例如 NSCache (,并在再次检索图像之前进行检查。

    我会确保与网络链接调节器一起测试此过程,以便您可以在不太理想的环境(即现实世界情况(中确认应用程序的行为。


与您的问题无关,异步更新单元格有两个问题:

    如果单元格在
  1. 图像检索完成时滚动到视图之外,则该单元格可能已被重复使用,并且该单元格可能已重新用于表中的另一行。(通过使用网络链接调节器运行应用程序来测试这一点,将网络响应时间降低到更糟糕的蜂窝连接器。此问题可能表现为图像的"闪烁"或用与其他单元格关联的图像替换图像。

    通常通过调用 tableView.cellForRowAtIndexPath(indexPath)(一种UITableView方法,不要与名称类似的 UITableViewDataSource 方法混淆(来解决此问题,如果此索引路径已滚动出屏幕,它将返回nil,如果单元格可见,则将返回UITableViewCell。在执行单元格的最终异步填充时,请使用此值而不是先前建立的cell值。

  2. 如果在异步检索图像的过程中有可能重新加载表(即数据源已更改(,则实际上可能希望返回到模型,标识与刚刚异步下载的图像关联的相应索引路径。

底线,想象一下一些退化的情况,需要一分钟左右的时间才能检索图像(不太可能,想象一下(。仔细考虑与此相关的意外情况(单元格滚动并随后重复使用,图像的 indexPath 可能不再有效等(。确保您优雅地处理这些突发事件。

最新更新