Swift 3:URL Image使UITableView滚动缓慢问题

时间:2017-06-13 11:12:38

标签: ios swift uitableview dispatch-async imageurl

我有一个在UIImageView上打印图片网址的扩展程序。但我认为问题是我的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)
            }
        }
    }
}

4 个答案:

答案 0 :(得分:2)

我认为,这里的问题是,您需要在table view中缓存图片以实现平滑滚动。每次程序调用{​​{1}}时,它都会再次下载图像。这需要时间。

对于缓存图片,您可以使用cellForRowAt indexPathKingfisher等库。

Kingfisher用法示例:

SDWebImage

希望有所帮助

答案 1 :(得分:2)

可以使用这里建议的框架,但你也可以考虑"滚动你自己的" this article

中描述的扩展程序

"所有"你需要做的是:

  1. 使用 public static HashMap<String, String> getContactsForGroup(String groupID, Activity activity){ Cursor dataCursor = activity.getContentResolver().query( ContactsContract.Data.CONTENT_URI, new String[]{ // PROJECTION ContactsContract.Data.CONTACT_ID, ContactsContract.Data.DISPLAY_NAME, // contact name ContactsContract.Data.DATA1 // group }, ContactsContract.Data.MIMETYPE + " = ? " + "AND " + // SELECTION ContactsContract.Data.DATA1 + " = ? ", // set groupID new String[]{ // SELECTION_ARGS ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE, groupID }, null ); dataCursor.moveToFirst(); HashMap<String, String> map = new HashMap<>(); while (dataCursor.moveToNext()) // { String s0 = dataCursor.getString(0); //contact_id String s1 = dataCursor.getString(1); //contact_name String s2 = dataCursor.getString(2); //group_id Log.d("tag", "contact_id: " + s0 + " contact: " + s1 + " groupID: "+ s2); map.put(s0, s1); } return map; } 下载您的图片,这是在后台线程上完成的,因此不会出现卡顿和慢速滚动。
  2. 完成后,在主线程上更新图像视图。
  3. 拿一个

    第一次尝试可能看起来像这样:

    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) 来向用户显示&#34;正在加载某些内容&#34;,如下所示:

    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 :) } extension,如下所示:

    UIImageView

    基本上它与以前的代码相同,但对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

    当然......包括SDWebImage或Kingfisher作为依赖关系更快,并且&#34;只是工作&#34;大多数情况下,它还为您提供其他好处,如缓存图像等。但我希望这个例子表明,为图像编写自己的扩展并不是那么糟糕......再加上你知道在不工作时应该责怪谁;)

    希望能帮到你。

答案 2 :(得分:1)

用于在后台缓存图像&amp;滚动更快使用SDWebImage

 imageView.sd_setImage(with: URL(string: "http://image.jpg"), placeholderImage: UIImage(named: "placeholder.png"))

https://github.com/rs/SDWebImage

答案 3 :(得分:1)

你的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)
                }
            }
        }
    }
 }
}