3

I need to have few different cell types in one quite complex table view. I registered 10 xib's with those different cell classes with different reuse identifiers. The problem is that when I scroll the table view for the first time (from top to bottom) then I can see it is lagging a little bit. However after I scrolled to the bottom, then scrolling back to the top and to the bottom again runs smoothly. The problems seems to be in dequeueReusableCellWithIdentifier: which does not seem to load different xib files fast enough while scrolling if there is no reusable cell of needed type at the moment. That's why first scrolls is lagging but when enough reusable cells of each type are loaded then it starts to scroll smoothly.

Is there any way to preload reusable cells for UITableView. So for example I could load each xib type 3 times (so tableview would have 30 reusable cells already loaded in memory (3 for each of 10 cell types) when there is a call to dequeueReusableCellWithIdentifier)? I will need to publish app on the app store later so any private api is not allowed. Or maybe you have any other possible solutions to improve performance in such case?

Leszek Szary
  • 9,763
  • 4
  • 55
  • 62
  • do you see lagging on simulator or only on device (what type of device / iOS version)? It also would be nice to check with Xcode Instruments if dequeueReusableCellWithIdentifier is actually problem. – f3n1kc Mar 11 '15 at 20:32
  • Lags both on similator and device (iphone 5 ios 8) but as I said only on first scroll from top to bottom. After full scroll it starts scrolling smoothly. Yes, I checked in instruments and it looks like dequeueReusableCellWithIdentifier is the problem. – Leszek Szary Mar 11 '15 at 20:41
  • You should register you cell xib by -[dequeueReusableCellWithIdentifier:(NSString *)identifier] in the UITableView instance. And you may need to override the -[prepareForReuse] in your custom cell class. So the cell instance would be reuse. Reduce the cell instance number will increase your speed. – Feng Lin Mar 13 '15 at 01:39

4 Answers4

1

If you are using storyboards in your app, you can define multiple cell types within the table definition once you declare the tableView's parent view controller as a UITableViewDelegate.

You are probably right that the initial load of the XIBs is killing you. enter image description here

Dan Loughney
  • 4,647
  • 3
  • 25
  • 40
  • Yes I need to have 10 different xib's with completely different layouts, so saying that I don't need them does not help me much :) Any other suggestions? – Leszek Szary Mar 11 '15 at 19:19
  • You can have 10 different layouts. You just have them in the same XIB. Look where the arrow is. You set the number of custom cells there. Then the XIB loads in one shot when the view controller is loaded and your issue should go away. – Dan Loughney Mar 11 '15 at 20:34
  • Do you mean that I should put different layouts one above another in one UITableViewCell below its Content View? Yes, that might solve too slow loading of cells while scrolling but it is not a very elegant solution and it would be hard to maintain, so I will look for other solution. – Leszek Szary Mar 11 '15 at 20:45
  • Yes. You see the list of Table View Cells on the left. Each can have its own layout. Each should have its own reuse identifier and you should absolutely rename the cells on the explorer for your own sanity. I agree that the UI can be a little tough to work with, but it is intended for your problem. I support an app with 10 different result types so we have 10 custom cell prototypes. – Dan Loughney Mar 11 '15 at 21:15
  • OK I see what you meant now. Thanks for suggestion. I'm not sure if that would help, but in project I'm working I can't use storyboard anyway and view controllers in xib's unfortunately do not support dynamic cell prototypes. – Leszek Szary Mar 12 '15 at 06:58
  • Unfortunately this is a picture of storyboard (you can see on xcode toolbar that this is Main.storyboard) and I'm actually sure you can't use dynamic cell prototypes in tableview in xib file. Anyway thanks for suggestions. – Leszek Szary Mar 12 '15 at 17:40
  • You're right. I thought I was in the XIB and was back in the storyboard. I'll update the answer to reflect this is just for storyboards. – Dan Loughney Mar 13 '15 at 01:24
1

As I recall, CoreGraphics will go through each cell as it first appears and performs some blending calculations to make the labels and views show as you've designed them.

Some of this slow-down can be alleviated by setting each view (label, button, view) to opaque in InterfaceBuilder.

Reduce the number of views that have alpha != 1.

Set backgrounds to white, or whatever color you're using instead of clear.

Check out this guy's explanation and sample code for how he makes scrolling as fast as it should be for pretty dynamic tableViews. https://github.com/kevinlawler/fastscrolling

*The link was kind of an old example, but the principles still apply afaik

Adama
  • 1,101
  • 8
  • 26
1

Creating a secondary cache with preloaded cells solved the scrolling problem. On viewDidLoad I'm registering nibs (with registerNib:forCellReuseIdentifier:) and right after that also in viewDidLoad I'm creating a mutable array and I use dequeueReusableCellWithIdentifier: to load few cell's for each nib and I put those cells in my mutable array. Later in cellForRowAtIndexPath I first check if I have preloaded cell with needed type in my mutable array. If I have it there then I return this cell and remove it from array (I do not call dequeueReusableCellWithIdentifier: in this case). If I do not have it in my cache then I call dequeueReusableCellWithIdentifier: to get the cell.

EDIT: It turned out that the main reason of lag were some simple reactive cocoa bindings that I had in awakeFromNib. After removing these reactive cocoa bindings everything started to scroll smoothly even without any additional cell preloading.

Leszek Szary
  • 9,763
  • 4
  • 55
  • 62
1

I'm using a trick way.

1) Add several zero height cell in the front of the actual one.

2) Dequeue it as what you want.

3) Set cell.clipToBounds to YES.

Now it's done.

wods
  • 11
  • 1