I have a UITableView in which each cell represents a user's post. The height of the cells is dynamic. The cell is customized, it has text fields, buttons and pictures (avatar and pictures of the post). This is all done through autolayout.

In each post images can be up to 10 pieces. And there can be an infinite number of posts. For post pictures, there is in each cell of UIView to which these same pictures are added, but they are compiled with tiles, something like in VK. Pictures on the server do not have a miniature version, they are all full-sized. And there may even be 1000x1000 in rare cases. But more often in a post there is only one picture approximately 600x600. If you comment out the output of pictures, then the table scrolls perfectly smoothly (well, almost). But with pictures, it “gets stuck” when scrolling during almost every scrolling.

I have a url for each picture. And with this method, I load the picture from the url and add it to the subview.

let picData: NSData = NSData(contentsOfURL: NSURL(string: picture.url! as String)!)! picIMG = UIImageView(frame: CGRect(x: xoffset, y: y, width: picture.resizeW, height: picture.resizeH)) picIMG.contentMode = .ScaleToFill picIMG.image = UIImage(data: picData) cell.viewVW.addSubview(picIMG) 

And I noticed that there are lags not only if there are pictures in the post. I tried to disable them and left only avatars (which are also downloaded from the Internet in each post). But it still slows down, even though the avatars are approximately up to 500x500 pixels in size.

Question: Maybe this is not quite the right way to load images via NSData(contentsOfURL: url) ? What is the best way to load pictures in such cases? Or maybe you need to independently upload pictures via NSURLSession or some other method and then display it already from the device?

Since everything works smoothly without pictures, the thing is still in pictures.

Updt: I tried to add the SDWebImage library for loading using the lazy method image loading. With avatars it helped, but with the loading of pictures of the post is not very, although it is still better than it was. Thanks for the tip @markov Avatar download code is as follows:

  if let avurl = post.useravatar { cell.avatarIMG.layer.cornerRadius = 30 cell.avatarIMG.clipsToBounds = true let url = NSURL(string: avurl) cell.avatarIMG.sd_setImageWithURL(url, placeholderImage: UIImage(named: "logo_anm_one.png")) } 

And this is the code where the pictures are added to the post. The principle is this: I create a UIImageView, assign it .sd_setImageWithURL and set the URL from which to download the image, and then add it to cell.viewVW as a subview. And so 10 pictures (if there are 10).

  let picsCount = allposts[indexPath.row].pic.count if picsCount > 0 { var xoffset = 0 var yoffset = 0 if picsCount > 3 { yoffset = post.pic[0].resizeH } for i in 1...picsCount { let picture = post.pic[i-1] let picData: NSData = NSData(contentsOfURL: NSURL(string: picture.url! as String)!)! var picIMG : UIImageView! var y = 0 if picsCount > 3{ if i > 2 { y = yoffset + 1 } if i == 3 { xoffset = 0 } } picIMG = UIImageView(frame: CGRect(x: xoffset, y: y, width: picture.resizeW, height: picture.resizeH)) xoffset += picture.resizeW + 1 picIMG.contentMode = .ScaleToFill let url = NSURL(string: picture.url! as String)! picIMG.sd_setImageWithURL(url, placeholderImage: UIImage(named: "logo_anm_one.png")) cell.viewVW.addSubview(picIMG) } var picblockH = CGFloat(post.pic[0].resizeH) if picsCount > 3 { picblockH += 1 + CGFloat(post.pic[2].resizeH) } let heightConstraint = NSLayoutConstraint(item: cell.viewVW, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: picblockH) cell.viewVW.addConstraint(heightConstraint) } else if picsCount == 0 { let heightConstraint = NSLayoutConstraint(item: cell.viewVW, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 1) cell.viewVW.addConstraint(heightConstraint) } 

Updt2:

As it turned out, when using the suggested method, I just forgot to comment out the line that was downloading the pictures in the old way:

 let picData: NSData = NSData(contentsOfURL: NSURL(string: picture.url! as String)!)! 
  • Most likely the fact is that you download multiple images at the same time, perhaps also in the main stream. Try to download them in another stream, I advise you to use the same cache, already for downloaded pictures, so that when you scroll in the opposite direction again, do not download the same pictures. Well, to reduce the number of requests, you can download only for the lines visible on the screen. - Vitali Eller
  • Well, yes in the same stream. I don't know exactly how NSData (contentsOfURL: url) works, but I thought it was working asynchronously. And it also turned out in practice that he himself caches pictures. And also this method is called when the cell is displayed on the screen. - cheerful_weasel
  • one
    This is NSData(contentsOfURL: - this is a synchronous web request, that's the problem. Use some lazy image libu, in no case can you use contentsOfURL for resources that aren't the ones on your device, this is a very bad style. Now there is little of time for a detailed answer, if you figure it out - write, then I will sign for the thread in more detail - Markov
  • Well, for now, I'll try searching for a lazy image. If that does not work then I ask. Thank. - cheerful_weasel
  • @markov I searched about the lazy image library. According to the description, I liked the alamofire image more, but it says that the version of Swift is from 3.0, and I have a 2.3 project. Of the rest, for me, the simplest at first glance was the SDWebImage library, I connected it. With avatars, it seems to be a ride, since for an avatar in each cell there is already a UIImageView. But for post images it is more difficult, since UIImageView is created programmatically and then added to UIView as a subview. 1. create a UIImageView, 2. add picIMG.sd_setImageWithURL (url, placeholderImage: UIImage (named: "-")) to it - cheerful_weasel

1 answer 1

You can get rid of lags when scrolling in UITableView in this way:

Swift 3

1 in

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

We give only cell .

2 in

 func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) 

Asynchronously fill the cells with data

You can fill it with data in cellForRowAt , but again, do it asynchronously.