简体   繁体   中英

Force UITableView to cache reusable cells

I use a table view with relatively 'heavy' custom table view cells - say there's is around 100 subviews in a single cell (full hierarchy). Despite of that I've been able to reach very smooth scrolling - using standart practices like working only with opaque views, hiding unused subviews (or even removing from the view hierarchy), pre-loading cells height etc.

The problem is that it's still relatively costly to create a single cell instance. Because of how the standard UITableView's cell reusage logic works this problem is only noticeable in specific conditions.

Usually when table view is loaded (and intitial content is displayed) it creates almost all required cells instances - so when you start scrolling it rarely needs to create any more reusable cells. But if for some reason it only displays a few cells at the beginning it would obviously need to create more when scrolling is initiated. In my case this is noticeable if there's a wide table view header or if first cells are big enough. When that happens once you start scrolling there's a noticeable lag for a few moments which is clearly caused by new cell instances being created. Nothing really ugly but still noticeable especially compared to absolutely smooth scrolling after that.

Now the obvious solution for that would be to make cells 'lighter' - like break them into different more specific types so each can contain less subviews. But because of the way my content is organized that would be a very complex solution.

So my question is - is there any good way to 'trick' table view logic to force loading and caching of specific number of reusable cell instances right away - despite of the number of cells actually visible?

One of the options I've been thinking of is to have own explicit cache of cells and pre-populate it with cells when needed (say in -viewDidLoad). The problem I have with this approach is that you have to known exact type of cells you will need beforehand - doesn't work well for me. The improvement would be to build cache when the initial data is loaded (so at least the exact type of content is known) but I've been wondering if there are any simple options.

You can do it by adding your own "secondary cache" layer to your data source.

When you initialize your data source, pre-create as many cells as needed, and put them into an array. When your dequeueReusableCellWithIdentifier fails, go for that array first, and take a cell from there. Once the array is exhausted, start creating new cells (if you create enough cells upfront, you shouldn't need to create new ones on the fly: dequeuing will eventually stop failing when you have enough cells rotating in and out of visibility).

I too had a similar situation wherein I wanted to load the several websites in different cells and loadrequest must be triggered only once. Idea is to avoid duplicate calls when the cell is made visible/invisible by scrolling up or down. say I have 5 cells in my tableview and each cell has a webview which loads the different websites. loadrequest will be called once and cell will be cached. here goes the simplest implementation.

Variable declaration

let weblinks:[String] = ["http://www.google.com",
                         "http://www.facebook.com",
                         "http://www.yahoo.com",
                         "http://www.puthiyathalaimurai.com/",
                         "http://www.github.com"]
var mycells:[MyTableViewCell] = [MyTableViewCell(),
                                 MyTableViewCell(),
                                 MyTableViewCell(),
                                 MyTableViewCell(),
                                 MyTableViewCell()]

CellForRow. I hope you know what it does,

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cellIdentifier = String(describing: MyTableViewCell.self)

    let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as? MyTableViewCell
    if cell?.isNewCell == true { //return from cache
        return mycells[indexPath.row]
    }
    cell?.title.text = weblinks[indexPath.row].uppercased()
    cell?.web.loadRequest(URLRequest(url: URL(string: weblinks[indexPath.row])!))
    cell?.isNewCell = true //mark it for cache
    mycells[indexPath.row] = cell!
    return cell!
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM