JEL JEL - 5 months ago 56
Swift Question

Reloading table causes flickering

I have a search bar and a table view under it. When I search for something a network call is made and 10 items are added to an array to populate the table. When I scroll to the bottom of the table, another network call is made for another 10 items, so now there is 20 items in the array... this could go on because it's an infinite scroll similar to Facebook's news feed.

Every time I make a network call, I also call

self.tableView.reloadData()
on the main thread. Since each cell has an image, you can see flickering - the cell images flash white.

I tried implementing this solution but I don't know where to put it in my code or how to. My code is Swift and that is Objective-C.

Any thoughts?

Update To Question 1

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(R.reuseIdentifier.searchCell.identifier, forIndexPath: indexPath) as! CustomTableViewCell

let book = booksArrayFromNetworkCall[indexPath.row]

// Set dynamic text
cell.titleLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
cell.authorsLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleFootnote)

// Update title
cell.titleLabel.text = book.title

// Update authors
cell.authorsLabel.text = book.authors

/*
- Getting the CoverImage is done asynchronously to stop choppiness of tableview.
- I also added the Title and Author inside of this call, even though it is not
necessary because there was a problem if it was outside: the first time a user
presses Search, the call for the CoverImage was too slow and only the Title
and Author were displaying.
*/
Book.convertURLToImagesAsynchronouslyAndUpdateCells(book, cell: cell, task: task)

return cell
}


cellForRowAtIndexPath
uses this method inside it:

class func convertURLToImagesAsynchronouslyAndUpdateCells(bookObject: Book, cell: CustomTableViewCell, var task: NSURLSessionDataTask?) {

guard let coverImageURLString = bookObject.coverImageURLString, url = NSURL(string: coverImageURLString) else {
return
}

// Asynchronous work being done here.
task = NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { (data, response, error) -> Void in

dispatch_async(dispatch_get_main_queue(), {

// Update cover image with data

guard let data = data else {
return
}

// Create an image object from our data
let coverImage = UIImage(data: data)
cell.coverImageView.image = coverImage
})
})

task?.resume()
}


When I scroll to the bottom of the table, I detect if I reach the bottom with
willDisplayCell
. If it is the bottom, then I make the same network call again.

override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {

if indexPath.row+1 == booksArrayFromNetworkCall.count {

// Make network calls when we scroll to the bottom of the table.
refreshItems(currentIndexCount)
}

}


This is the network call code. It is called for the first time when I press Enter on the search bar, then it is called everytime I reach the bottom of the cell as you can see in
willDisplayCell
.

func refreshItems(index: Int) {

// Make to network call to Google Books
GoogleBooksClient.getBooksFromGoogleBooks(self.searchBar.text!, startIndex: index) { (books, error) -> Void in

guard let books = books else {
return
}

self.footerView.hidden = false

self.currentIndexCount += 10

self.booksArrayFromNetworkCall += books

dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}

Answer

If only the image flash white, and the text next to it doesn't, maybe when you call reloadData() the image is downloaded again from the source, which causes the flash. In this case you may need to save the images in cache.

I would recommend to use SDWebImage to cache images and download asynchronously. It is very simple and I use it in most of my projects. To confirm that this is the case, just add a static image from your assets to the cell instead of calling convertURLToImagesAsynchronouslyAndUpdateCells, and you will see that it will not flash again.

I dont' program in Swift but I see it is as simple as cell.imageView.sd_setImageWithURL(myImageURL). And it's done!

Comments