2

I have this problem about 3-4 weeks. I googled , checked everything but still not working. Please help me!

On every moving scroll cellForRowAtIndexPath reloads tableView so , it start freezing.

My tableview for cellForRowAtIndexPath function is like this:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{

    let cell = tableView.dequeueReusableCellWithIdentifier("cell")! as! MoviesTVC
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),{
        let dictionary = self.rows[indexPath.row] as? [String: AnyObject]
        dispatch_async(dispatch_get_main_queue(),{
            cell.setCell(dictionary!)
        })

    })

    return cell
}

The setCell() function:

func setCell(dictionary: AnyObject){
    let ImgString = dictionary["src"] as? String;
    let ImgUrl = NSURL(string: ImgString!);
    let ImgData = NSData(contentsOfURL: ImgUrl!)
    self.movImg.image = UIImage(data: ImgData!);
    self.movName.text = dictionary["name"] as? String;
    self.movComment.text = dictionary["caption"] as? String;
}
  • In addition to Putz1103's observation below, this process of updating the cell asynchronously is more complicated than your code (or his) contemplates. You should consider (a) cell reused by time async request is done; (b) fast scroll where visible cell image requests are backlogged behind pending requests for cells that have scrolled out of view; etc. See To do all of this well is non-trivial and you might consider a `UIImage` extension that handles asynchronous image retrieval more gracefully. See http://stackoverflow.com/a/33505649/1271826. – Rob May 13 '16 at 20:22
  • You should probably check to whether the cell still corresponds to the given index path after the async call (maybe it's scrolled offscreen). Also, avoid using the ! operator, maybe you should use an "if let" – Glenn Howes May 13 '16 at 20:59

1 Answers1

4

You have the wrong bits of code in background async tasks. Currently you are only getting a value from your array in the background, which is a very very fast process...

What you should do is run the difficult tasks in the background, then update the UI in the foreground.

let cell = tableView.dequeueReusableCellWithIdentifier("cell")! as! MoviesTVC
let dictionary = self.rows[indexPath.row] as? [String: AnyObject]
cell.setCell(dictionary!)

return cell


func setCell(dictionary: AnyObject){
    let ImgString = dictionary["src"] as? String;
    let ImgUrl = NSURL(string: ImgString!);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),{
        let ImgData = NSData(contentsOfURL: ImgUrl!)
        let image = UIImage(data: ImgData!);
        //Possibly resize the image here in the background task
        //so that the cpu doesn't need to scale it in the UI thread
        dispatch_async(dispatch_get_main_queue(),{
            self.movImg.image = image
        })
    })
    self.movName.text = dictionary["name"] as? String;
    self.movComment.text = dictionary["caption"] as? String;
}

Edit: To answer your question in comments. The easiest solution would be to add an attribute to the dictionary for each cell that is "image". Then when you are loading the cell if the "image" attribute of the dictionary exists then you can just load that image into your cell. If it doesn't exist then download it and save it to the dictionary, then add it to your cell.

A harder solution to that would be to download the images to a local resource location. Then use imageNamed to load the image from file. This will take care of caching and memory releasing for you. That would be the better option.

Even better would be to use CoreData. In any of these solutions you will have to manage clearing file storage when you are running low.

Putz1103
  • 6,211
  • 1
  • 18
  • 25
  • Thanks!Freezing problem solved , but in this case images downloading on every moving scroll. I mean, setCell() function calling during scrolling. Do you have any suggestion ? – Jeyhun Ashurbayov May 13 '16 at 20:20
  • @CeyhunAshurbeyli - You generally do want to initiate the image request as you scroll (e.g. you scroll down to show three more rows, so you do want those images to be requested immediately). The trick is that you want to stop the requests for cells that have scrolled off screen, but haven't yet finished downloading the image. And that means not using `NSData(contentsOfURL:)`. There are tons of nice `UIImageView` extensions that handle this stuff gracefully and get you out of the weeds. – Rob May 13 '16 at 20:32
  • @Putz1103 Thank you very much! I will check first suggestion now. I m thinking to do second in the future. – Jeyhun Ashurbayov May 13 '16 at 20:34