Swift Image下载TableView

时间:2017-06-06 14:47:05

标签: ios swift image uitableview download

我正在尝试解决在Swift中的TableView中异步下载图像的问题。这是我的问题:我从一个url异步下载图像,但如果我快速滚动TableView我的图片开始旋转。(图像交替,直到出现正确的图像)。

这是我的下载异步代码和imageCache

let imageCache = NSCache()

//DOWNLOAD Image ASINC
extension UIImageView {

    public func imageFromServerURL(url: String){

        if(imageCache.objectForKey(url) != nil){
            self.image = imageCache.objectForKey(url) as? UIImage
        }else{

            let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
            let session = NSURLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
            let task = session.dataTaskWithURL(NSURL(string: url)!, completionHandler: { (data, response, error) -> Void in
                if error == nil {

                    dispatch_async(dispatch_get_main_queue(), { () -> Void in
                        if let downloadedImage = UIImage(data: data!) {
                            imageCache.setObject(downloadedImage, forKey: url)
                            self.image = downloadedImage
                        }
                    })

                }
                else {
                    print(error)
                }
            })
            task.resume()
        }

    }
}

我在TableView中回忆起来:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("record_charts", forIndexPath: indexPath) as! myTableViewCell

            let url_img = "https://image/download.jpg"
            cell.immagine.imageFromServerURL(url_img)


        return cell
    }

这是向您展示更好问题的GIF Gif Problem

3 个答案:

答案 0 :(得分:2)

这是由于iOS表视图的重用机制。 您可以对代码进行一些修改以解决此问题:

class AsyncImageView: UIImageView {

private var currentUrl: String? //Get a hold of the latest request url

public func imageFromServerURL(url: String){
    currentUrl = url
    if(imageCache.objectForKey(url) != nil){
        self.image = imageCache.objectForKey(url) as? UIImage
    }else{

        let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
        let session = NSURLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
        let task = session.dataTaskWithURL(NSURL(string: url)!, completionHandler: { (data, response, error) -> Void in
            if error == nil {

                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    if let downloadedImage = UIImage(data: data!) {
                        if (url == currentUrl) {//Only cache and set the image view when the downloaded image is the one from last request
                            imageCache.setObject(downloadedImage, forKey: url)
                            self.image = downloadedImage
                        }

                    }
                })

            }
            else {
                print(error)
            }
        })
        task.resume()
    }

}
}

注意#1:我对修改进行了白板编码,因此不确定代码是否具有正确的语法。

注意#2:您可以使用关联的 对象,而不是声明UIImageView的新子类。

注意#3:我强烈建议您使用AlamoFireImage,它有一个UIImageView类别,这正是您在这种情况下所需要的(以及未来的情况)。

答案 1 :(得分:1)

这是因为细胞重复使用。我会尽力解释。假设您有10个单元格,每个单元格具有不同的图像(图像1到10),但屏幕上只有5个单元格。该表开始加载,并且第一个单元格请求将图像1放入图像视图中并且开始在后台进行,但是在图像的后台加载完成并且第一个单元格滚动屏幕之前滚动该表格。现在该单元将被重复使用,请说出请求图像6的第六单元。然后,对图像1的后台请求结束,并且当它仍然保持对单元图像1的引用时,将其放入图像视图中。然后,您的图像6的后台处理完成,并用新版本替换图像。如果图像6在图像1之前完成加载,那么情况会更糟,然后将图像6放入单元格中,然后由图像1替换。

您需要做的是实现一些方法,以便在图像可用时您可以检查它是否仍然是正确使用的。我不认为你能够做到这一点,使该功能成为ImageView的扩展,所以你可能需要某种中央图像提供者或类似的东西。

答案 2 :(得分:0)

您需要在UIImageView扩展程序中添加取消方法,然后在tableView(_:willDisplay:forRowAt:)prepareForReuse()UITableViewCellSELECT lead.id, first, last, lead.phone, valid_phone, mobile_phone FROM lead LEFT JOIN dnt ON dnt.phone = lead.phone LEFT JOIN areacode ON areacode.code = LEFT(lead.phone, 3) LEFT JOIN campaign ON campaign.id = lead.campaign_id WHERE dnt.id IS NULL AND campaign.lft BETWEEN 0 AND 1000 AND lead.datetime BETWEEN '2017-06-01 00:00:00' AND '2017-06-01 23:59:59' AND areacode.hours = 2 GROUP BY lead.phone ORDER BY lead.phone DESC LIMIT 1,1000 中调用}

或者您可以取消SDWebImage的网络缓存

中的请求