Swift 3:URL Image使UITableView滚动缓慢问题
我有一个在UIImageView
上打印图像URL的扩展。 但我认为问题是我的tableView
因为这个扩展而太慢了。 我想我需要为它打开线程。 如何在此扩展中创建一个线程,或者您是否知道另一个解决此问题的解决方案?
我的代码:
extension UIImageView{ func setImageFromURl(stringImageUrl url: String){ if let url = NSURL(string: url) { if let data = NSData(contentsOf: url as URL) { self.image = UIImage(data: data as Data) } } } }
我认为,这里的问题是,您需要在table view
缓存图像以实现平滑滚动。 每次程序调用cellForRowAt indexPath
它都会再次下载图像。 这需要时间。
对于缓存图像,您可以使用SDWebImage
, Kingfisher等库。
翠鸟用法示例:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) as! CustomCell cell.yourImageView.kf.setImage(with: URL) // next time, when you will use image with this URL, it will be taken from cache. //... other code }
希望能帮助到你
您可以按照此处的建议使用框架,但您也可以考虑本文所述的“滚动自己的”扩展
你需要做的“全部”是:
- 使用
URLSession
下载您的图像,这是在后台线程上完成的,所以没有口吃和慢滚动。 - 完成后,更新主线程上的图像视图。
拿一个
第一次尝试可能看起来像这样:
func loadImage(fromURL urlString: String, toImageView imageView: UIImageView) { guard let url = URL(string: urlString) else { return } //Fetch image URLSession.shared.dataTask(with: url) { (data, response, error) in //Did we get some data back? if let data = data { //Yes we did, update the imageview then let image = UIImage(data: data) DispatchQueue.main.async { imageView.image = image } } }.resume() //remember this one or nothing will happen :) }
你可以这样调用这个方法:
loadImage(fromURL: "yourUrlToAnImageHere", toImageView: yourImageView)
起色
如果你想要它,你可以添加一个UIActivityIndicatorView
来向用户显示“正在加载的东西”,如下所示:
func loadImage(fromURL urlString: String, toImageView imageView: UIImageView) { guard let url = URL(string: urlString) else { return } //Add activity view let activityView = UIActivityIndicatorView(activityIndicatorStyle: .gray) imageView.addSubview(activityView) activityView.frame = imageView.bounds activityView.translatesAutoresizingMaskIntoConstraints = false activityView.centerXAnchor.constraint(equalTo: imageView.centerXAnchor).isActive = true activityView.centerYAnchor.constraint(equalTo: imageView.centerYAnchor).isActive = true activityView.startAnimating() //Fetch image URLSession.shared.dataTask(with: url) { (data, response, error) in //Done, remove the activityView no matter what DispatchQueue.main.async { activityView.stopAnimating() activityView.removeFromSuperview() } //Did we get some data back? if let data = data { //Yes we did, update the imageview then let image = UIImage(data: data) DispatchQueue.main.async { imageView.image = image } } }.resume() //remember this one or nothing will happen :) }
延期
本文中提到的另一个改进可能是将其移动到UIImageView
上的extension
,如下所示:
extension UIImageView { func loadImage(fromURL urlString: String) { guard let url = URL(string: urlString) else { return } let activityView = UIActivityIndicatorView(activityIndicatorStyle: .gray) self.addSubview(activityView) activityView.frame = self.bounds activityView.translatesAutoresizingMaskIntoConstraints = false activityView.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true activityView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true activityView.startAnimating() URLSession.shared.dataTask(with: url) { (data, response, error) in DispatchQueue.main.async { activityView.stopAnimating() activityView.removeFromSuperview() } if let data = data { let image = UIImage(data: data) DispatchQueue.main.async { self.image = image } } }.resume() } }
基本上它与以前的代码相同,但对imageView
引用已更改为self
。
你可以像这样使用它:
yourImageView.loadImage(fromURL: "yourUrlStringHere")
当然……包括SDWebImage或Kingfisher作为依赖项更快,并且“大部分时间都可以正常工作”,此外它还可以为您提供其他好处,例如缓存图像等等。 但我希望这个例子表明,为图像编写自己的扩展并不是那么糟糕……再加上你知道在不工作时应该责怪谁;)
希望对你有所帮助。
你的tableview很慢,因为你在主线程的当前线程中加载数据。 您应该加载其他线程的数据,然后在主线程中设置图像(因为所有UI作业必须在主线程中完成)。 您不需要使用第三方库,只需更改您的扩展程序:
extension UIImageView{ func setImageFromURl(stringImageUrl url: String){ if let url = NSURL(string: url) { DispatchQueue.global(qos: .default).async{ if let data = NSData(contentsOf: url as URL) { DispatchQueue.main.async { self.image = UIImage(data: data as Data) } } } } } }
对于在后台缓存图像和滚动更快,请使用SDWebImage
库
imageView.sd_setImage(with: URL(string: "http://sofzh.miximages.com/ios/image.jpg"), placeholderImage: UIImage(named: "placeholder.png"))