Je travaille sur show image from url async. J'ai essayé de créer un nouveau fil pour l'image de téléchargement, puis d'actualiser le 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
}
}
}
Lorsque j’essayais de déboguer cela, quand il s’agissait de dispatch_async (downloadQueue), cela saute aux yeux. Toute suggestion? THX
Swift 3.0+ mis à jour le Code :( a pris l’aide de jamesrochabrun Link https://github.com/jamesrochabrun/JSONTutorialFinal )
let imageCache = NSCache<NSString, UIImage>()
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 Code mis à jour:
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()
}}
Swift 2.2 Code:
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()
}}
Maintenant, partout où vous en avez besoin, faites ceci pour charger l'image à partir de l'URL du serveur:
Utilisation de Swift 3.0 + du code mis à jour à l'aide de l'image de marque de réservation: UIImageView.imageFromServerURL (URLString: "URL du serveur", placeHolder: image de marque de réservation au format uiimage)
Swfit 3 ou moins: UIImageView.imageFromServerURL ("ici URL du serveur")
Simple!
Utilisez extension
dans Swift3
. Pour résoudre Problème de réseau i vous recommande d'utiliser NSCache
:
import UIKit
let imageCache = NSCache<NSString, AnyObject>()
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()
}
}
J'espère que ça aide!
En reprenant la réponse de Shobhakar Tiwari, je pense qu'il est souvent utile dans ces cas de disposer d'une image par défaut en cas d'erreur et pour le chargement, je l'ai donc mise à jour pour inclure une image par défaut facultative:
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()
}
}
Cette solution rend le défilement très rapide sans mise à jour inutile des images . Vous devez ajouter la propriété url à notre classe de cellules:
class OfferItemCell: UITableViewCell {
@IBOutlet weak var itemImageView: UIImageView!
@IBOutlet weak var titleLabel: UILabel!
var imageUrl: String?
}
Et ajouter une extension:
import Foundation
import UIKit
let imageCache = NSCache<AnyObject, AnyObject>()
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
}
}
})
}
}
}
Vous pouvez également l'améliorer et extraire du code dans une classe de cellule plus générale, à savoir CustomCellWithImage, pour le rendre plus réutilisable.
La méthode la plus courante pour charger in Swift 4
des images asynchrones sans effet blink
ou changing images
consiste à personnaliser la classe UIImageView
comme celle-ci:
//MARK: - 'asyncImagesCashArray' is a global varible cashed UIImage
var asyncImagesCashArray = NSCache<NSString, UIImage>()
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()
}
}
exemple d'utilisation de cette classe dans UITableViewCell
ci-dessous:
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()
}
}
Ici, ce code pourrait vous aider.
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
})
}
}
})
}
Avec cette image va télécharger et mettre en cache sans retarder le défilement de la vue tableau
L'un des meilleurs moyens est d'utiliser SDWebImage .
Exemple rapide:
import SDWebImage
imageView.sd_setImage(with: URL(string: "ImageUrl"), placeholderImage: UIImage(named: "placeholder.png"))
Exemple d'objectif C:
#import <SDWebImage/UIImageView+WebCache.h>
[imageView sd_setImageWithURL:[NSURL URLWithString:@"ImageUrl"]
placeholderImage:[UIImage imageNamed:@"placeholder.png"]];