Imagem de carregamento asynchronous Swift

Estou trabalhando em show image from url async. Eu tentei criar um novo segmento para a imagem de download e, em seguida, atualizar no main thread .

 func asyncLoadImg(product:Product,imageView:UIImageView){ let downloadQueue = dispatch_queue_create("com.myApp.processdownload", nil) dispatch_async(downloadQueue){ let data = NSData(contentsOfURL: NSURL(string: product.productImage)!) var image:UIImage? if data != nil{ image = UIImage(data: data!) } dispatch_async(dispatch_get_main_queue()){ imageView.image = image } } } 

Quando eu estava tentando depurar isso, quando se trata de dispatch_async (downloadQueue), ele salta a function. Alguma sugestão? THX

Swift 3.0+ atualizado Código 🙁 teve ajuda de jamesrochabrun Link https://github.com/jamesrochabrun/JSONTutorialFinal )

 let imageCache = NSCache() extension UIImageView { func imageFromServerURL(_ URLString: String, placeHolder: UIImage?) { self.image = nil if let cachedImage = imageCache.object(forKey: NSString(string: URLString)) { self.image = cachedImage return } if let url = URL(string: URLString) { URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in //print("RESPONSE FROM API: \(response)") if error != nil { print("ERROR LOADING IMAGES FROM URL: \(error)") DispatchQueue.main.async { self.image = placeHolder } return } DispatchQueue.main.async { if let data = data { if let downloadedImage = UIImage(data: data) { imageCache.setObject(downloadedImage, forKey: NSString(string: URLString)) self.image = downloadedImage } } } }).resume() } } } 

Swift 3 Atualizado Código:

 extension UIImageView { public func imageFromServerURL(urlString: String) { self.image = nil URLSession.shared.dataTask(with: NSURL(string: urlString)! as URL, completionHandler: { (data, response, error) -> Void in if error != nil { print(error) return } DispatchQueue.main.async(execute: { () -> Void in let image = UIImage(data: data!) self.image = image }) }).resume() }} 

Código Swift 2.2:

  extension UIImageView { public func imageFromServerURL(urlString: String) { self.image = nil NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: urlString)!, completionHandler: { (data, response, error) -> Void in if error != nil { print(error) return } dispatch_async(dispatch_get_main_queue(), { () -> Void in let image = UIImage(data: data!) self.image = image }) }).resume() }} 

Agora, sempre que você precisar, faça isso para carregar a imagem do URL do servidor:

  1. Usando o código swift 3.0 + atualizado usando a imagem do espaço reservado: UIImageView.imageFromServerURL (URLString: “URL do servidor aqui”, placeHolder: imagem do espaço reservado no formato uiimage)

  2. Swfit 3 ou menos: UIImageView.imageFromServerURL (“here server url”)

Simples!

Use a extension no Swift3 . Para resolver o problema de rede, eu recomendo que você use o NSCache :

 import UIKit let imageCache = NSCache() extension UIImageView { func loadImageUsingCache(withUrl urlString : String) { let url = URL(string: urlString) self.image = nil // check cached image if let cachedImage = imageCache.object(forKey: urlString as NSString) as? UIImage { self.image = cachedImage return } // if not, download image from url URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in if error != nil { print(error!) return } DispatchQueue.main.async { if let image = UIImage(data: data!) { imageCache.setObject(image, forKey: urlString as NSString) self.image = image } } }).resume() } } 

Espero que ajude!

Continuando a partir da resposta de Shobhakar Tiwari, acho que é útil nesses casos ter uma imagem padrão em caso de erro e, para fins de carregamento, atualizei-a para include uma imagem padrão opcional:

Swift 3

 extension UIImageView { public func imageFromServerURL(urlString: String, defaultImage : String?) { if let di = defaultImage { self.image = UIImage(named: di) } URLSession.shared.dataTask(with: NSURL(string: urlString)! as URL, completionHandler: { (data, response, error) -> Void in if error != nil { print(error ?? "error") return } DispatchQueue.main.async(execute: { () -> Void in let image = UIImage(data: data!) self.image = image }) }).resume() } } 

Aqui este código pode ajudá-lo.

  let cacheKey = indexPath.row if(self.imageCache?.objectForKey(cacheKey) != nil){ cell.img.image = self.imageCache?.objectForKey(cacheKey) as? UIImage }else{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { if let url = NSURL(string: imgUrl) { if let data = NSData(contentsOfURL: url) { let image: UIImage = UIImage(data: data)! self.imageCache?.setObject(image, forKey: cacheKey) dispatch_async(dispatch_get_main_queue(), { cell.img.image = image }) } } }) } 

Com esta imagem irá baixar e armazenar em cache sem atrasar a rolagem de exibição de tabela

A maneira mais comum in SWIFT 4 para carregar imagens assíncronas sem blink ou changing images efeito de changing images é usar a class UIImageView personalizada como esta:

 //MARK: - 'asyncImagesCashArray' is a global varible cashed UIImage var asyncImagesCashArray = NSCache() class AyncImageView: UIImageView { //MARK: - Variables private var currentURL: NSString? //MARK: - Public Methods func loadAsyncFrom(url: String, placeholder: UIImage?) { let imageURL = url as NSString if let cashedImage = asyncImagesCashArray.object(forKey: imageURL) { image = cashedImage return } image = placeholder currentURL = imageURL guard let requestURL = URL(string: url) else { image = placeholder; return } URLSession.shared.dataTask(with: requestURL) { (data, response, error) in DispatchQueue.main.async { [weak self] in if error == nil { if let imageData = data { if self?.currentURL == imageURL { if let imageToPresent = UIImage(data: imageData) { asyncImagesCashArray.setObject(imageToPresent, forKey: imageURL) self?.image = imageToPresent } else { self?.image = placeholder } } } else { self?.image = placeholder } } else { self?.image = placeholder } } }.resume() } } 

exemplo de uso desta class no UITableViewCell abaixo:

 class CatCell: UITableViewCell { //MARK: - Outlets @IBOutlet weak var catImageView: AyncImageView! //MARK: - Variables var urlString: String? { didSet { if let url = urlString { catImageView.loadAsyncFrom(url: url, placeholder: nil) } } } override func awakeFromNib() { super.awakeFromNib() } } 

Esta solução torna a rolagem muito rápida sem atualizações de imagem desnecessárias. Você precisa adicionar a propriedade url à nossa class de célula:

 class OfferItemCell: UITableViewCell { @IBOutlet weak var itemImageView: UIImageView! @IBOutlet weak var titleLabel: UILabel! var imageUrl: String? } 

E adicione extensão:

 import Foundation import UIKit let imageCache = NSCache() let imageDownloadUtil: ImageDownloadUtil = ImageDownloadUtil() extension OfferItemCell { func loadImageUsingCacheWithUrl(urlString: String ) { self.itemImageView.image = nil if let cachedImage = imageCache.object(forKey: urlString as AnyObject) as? UIImage { self.itemImageView.image = cachedImage return } DispatchQueue.global(qos: .background).async { imageDownloadUtil.getImage(url: urlString, completion: { image in DispatchQueue.main.async { if self.imageUrl == urlString{ imageCache.setObject(image, forKey: urlString as AnyObject) self.itemImageView.image = image } } }) } } } 

Você também pode melhorá-lo e extrair algum código para uma class de célula mais geral, ou seja, CustomCellWithImage para torná-lo mais reutilizável.

Uma das melhores maneiras é usar o SDWebImage .

Exemplo Swift:

 import SDWebImage imageView.sd_setImage(with: URL(string: "ImageUrl"), placeholderImage: UIImage(named: "placeholder.png")) 

Exemplo de objective C:

 #import  [imageView sd_setImageWithURL:[NSURL URLWithString:@"ImageUrl"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];