Ios Swift图像下载表视图

Ios Swift图像下载表视图,ios,swift,image,uitableview,download,Ios,Swift,Image,Uitableview,Download,我正在尝试修复在Swift的TableView中异步下载图像的问题。这就是我的问题:我从一个url异步下载图像,但是如果我快速滚动TableView,我的图片就会开始旋转。(图像会交替出现,直到正确的图像出现) 这是我下载的异步代码和imageCache let imageCache = NSCache() //DOWNLOAD Image ASINC extension UIImageView { public func imageFromServerURL(url: String

我正在尝试修复在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,可以更好地显示问题
这是因为细胞重复使用。我会尽力解释的。假设您有10个单元格,每个单元格具有不同的图像(图像1到10),但屏幕上只能容纳5个单元格。表格开始加载,第一个单元格请求将图像1放在图像视图中,这在后台开始发生,但表格在图像的后台加载完成之前滚动,第一个单元格在屏幕上滚动。现在,该单元将被重用,比如说第六个单元请求图像6。然后,您对图像1的背景请求完成,并且由于它仍然保留对单元图像1的引用,因此将图像1放入图像视图中。然后图像6的背景处理完成,并用新版本替换图像。如果图像6在图像1之前完成加载,情况会更糟,因为您将图像6放入单元格中,然后将其替换为图像1


您需要做的是实现一些方法,这样当图像可用时,您可以检查它是否仍然是要使用的正确图像。我不认为您能够将该功能作为ImageView的扩展,因此您可能需要某种中央图像提供程序或类似的功能。

这是因为单元重用。我会尽力解释的。假设您有10个单元格,每个单元格具有不同的图像(图像1到10),但屏幕上只能容纳5个单元格。表格开始加载,第一个单元格请求将图像1放在图像视图中,这在后台开始发生,但表格在图像的后台加载完成之前滚动,第一个单元格在屏幕上滚动。现在,该单元将被重用,比如说第六个单元请求图像6。然后,您对图像1的背景请求完成,并且由于它仍然保留对单元图像1的引用,因此将图像1放入图像视图中。然后图像6的背景处理完成,并用新版本替换图像。如果图像6在图像1之前完成加载,情况会更糟,因为您将图像6放入单元格中,然后将其替换为图像1


您需要做的是实现一些方法,这样当图像可用时,您可以检查它是否仍然是要使用的正确图像。我认为您无法将该函数作为ImageView的扩展,因此您可能需要某种中央图像提供程序或类似的东西。

您需要在
UIImageView
扩展中添加取消方法,并调用它或在
表视图中(u:willDisplay:forRowAt:)
或在
prepareforeuse中调用它()
of
UITableViewCell


或者您可以在的web缓存中取消请求

您需要在
UIImageView
扩展中添加取消方法,并在
tableView中调用它或调用它(将显示:forRowAt:)
或在
UITableViewCell的
prepareForReuse()


或者您可以在的web缓存中取消请求,这是由于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提供了一个类别,这正是您在这种情况下(以及将来的情况下)所需要的。

这是由于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提供了一个类别,这正是您在这种情况下(以及未来的情况下)所需要的.

检查此问题:。这是在object-c中,它不起作用…您可以大致了解问题的来源。不幸的是,它不起作用检查此问题:。这是在object-c中,它不起作用…您可以大致了解问题的来源。不幸的是,它不起作用