13

I just downloaded Xcode6 Beta6 and found some strange defects in my App. After some initial debugging, I have found that heightForRowAtIndexPath is called numerous extra times and is causing some ill effects.

Normally, I would expect heightForRowAtIndexPath to be called 2 extra times than the rows I am displaying. So when I hardcode numberOfRowsInSection to return 3, I should be seeing heightForRowAtIndexPath get called 5 times. In iOS 7 that is the case, but when I test in Xcode6 Beta6 I am seeing heightForRowAtIndexPath get called 7 times. When I return 4, the method gets called 9, 5 and its 11. So it seems the pattern is twice the number of rows I am hardcoding + 1.

Has anyone else encountered this problem or found a way to solve it? Just being able to confirm that this is an iOS bug would be a huge help because then I can defer the defect for later as Apple may fix this problem on their own.


Edit: This issue still exists in Xcode 6 GM


Edit 2: Apple responded and closed my bug report, here is there response:

The API contract of a delegate is that we can call this method as much as we want.

I guess we just have to deal with this and should code to not rely on exactly when this delegate is called.

Rui Peres
  • 25,741
  • 9
  • 87
  • 137
bmjohns
  • 6,344
  • 1
  • 33
  • 39
  • Well that's a doozy! – angerboy Aug 21 '14 at 21:48
  • Probably worth [filing a radar](http://radar.apple.com). – Zev Eisenberg Aug 21 '14 at 21:54
  • Zev, just filled one out. I will update when I hear back from Apple. – bmjohns Aug 22 '14 at 18:23
  • 1
    i'm having same issue even on Beta 7 – DevCali Sep 02 '14 at 20:51
  • I have other but related problem: until iOS 7 if you didn't implemented heightForRowAtIndexPath (it is an @optional method) then the cell just took its height from the XIB defaults. Now it seems it takes 0 default value causing all cells to be collapsed one on other. – MrTJ Sep 16 '14 at 13:14
  • 2
    @MrTJ I had the same problem but it is not what I was describing above. In iOS 8 table row's resize themselves to fit the content that is inside them by default. Before they used to have a default size of 44, I set the tableView.rowHeight = 44 and they appeared normal for me again. Also for the problem above I am still seeing this happen in GM, might just be a new handling I had to create a workaround that didn't use heightForRow in the same way as before.. – bmjohns Sep 16 '14 at 18:51
  • Am using Xcode6.1 and have the same problem only on iOS 8 and above. Any work-around for this? – instaable Nov 10 '14 at 11:36
  • 1
    @instaable sorry, I just found a workaround that was specific to my problem. I was using this method to toggle a global property and change the height of my cell based on that variables status. I changed the global property be stored in each custom cell object instead. So it didn't matter if heightForRow was called extra times. – bmjohns Nov 11 '14 at 13:14
  • Weird. That's unfortunate; this seems like a really dumb bug on the part of Apple. But anyway, apart from the obvious inefficiency of invoking the method more times than is necessary, is this actually a real problem? Just curious. – Todd Lehman Apr 04 '16 at 15:57

2 Answers2

12

iOS 8 onwards, Apple has changed the way they decide the content size of a table view. This is to optimize it further and enable us to have more dynamism in the table design.

As part of this, they now no longer call heightForRowAtIndex path for all the rows in one shot, instead they just call it as many times as they want in order to determine the content size. The content size determination has also been made kind of dynamic, hence the multiple calls.

Don't do any height calculations inside the heightForRowAtIndexPath method. Instead write a private method and treat it as the heightForRowAtIndexPath of the past. Store all the heights in a dictionary against an NSIndexPath object as key.

Of course, this would mean to call this private method before calling reloadData, if the data has changed.

Deepak G M
  • 1,650
  • 17
  • 12
  • Wow, thank you. This just saved me about 200ms of loading time for a tableview I'm using (it's got 16 cells with wildly different heights at different times). – waffles Oct 07 '15 at 17:34
  • @deepak-g-m does this apply to UICollectionView too? – Halpo Apr 04 '16 at 14:22
3

For me, the dynamic height of the custom tableViewCells was causing an issue, to be specific, the heightForRowAtIndexPath and estimatedHeightForRowAtIndexPath delegate methods. One worked perfect for iOS 7 and the other for iOS 8. Solved it by conditionally checking for the iOS version.

EDIT: Since we had to support both iOS 7 and 8, with the Beta version of Xcode6 and our project submission the next day, this answer was the solution for me in mid 2014. If downvoting, please care to give the reason.

instaable
  • 3,449
  • 2
  • 24
  • 31
  • 1
    Can you please share how you conditionally call the above two delegates. I am facing the same issue.... – Rachit Dec 04 '14 at 11:12