2

I was having issues with my cell background image being distorted, and after having it answered I then went to implement the solution which basically consisted of shortening the height of the specific offending cells (that automatically had height added to them). I did this as follows:

- (CGFloat)tableView:(UITableView *)tableView 
  heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    CGFloat standardHeight = 44.0;

    if ([tableView numberOfRowsInSection:indexPath.section] == 1) {
        standardHeight -= 2;
    }

    return standardHeight;
}

However, every time I run that, I get caught in some sort of execution loop, where the app keeps bouncing back between the first line of that method and the start of the if statement until it crashes.

Video: http://f.cl.ly/items/2F1E3r2A2p0y1b2j3R14/debug.mov

However, if I use something like this (one of the answers in the previous thread) it seems to work:

- (CGFloat)tableView:(UITableView *)tableView 
  heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    CGFloat rowHeight = 44.0f;
    if (indexPath.row == 0) {
        rowHeight -=1;
    }
    return rowHeight;
}

What am I doing wrong? I just can't figure it out.

Community
  • 1
  • 1
Doug Smith
  • 29,668
  • 57
  • 204
  • 388

2 Answers2

6

The problem here is that you shouldn't rely on one datasource/delegate method to provide data to the other. What is essentially happening is that you are asking your tableView how many rows it has in a section, when you should be getting this information from your model (which is from where numberOfRowsInSection: should be getting it from as well)

All your datasource methods should just return data directly from the model, since your tableView may ask your datasource for data on unexpected times. That is true not only for UITableView but for all datasource based views, such as UICollectionView for example.

Cezar
  • 55,636
  • 19
  • 86
  • 87
  • What do you mean by getting it from my model? In this case I have very few cells being created (two at most, normally one) as it's a table for showing services to log in to. There's only two services to log in to now, so it just chooses what to show based on what ones you haven't logged into yet. https://gist.github.com/anonymous/cdc55c17de14c97d9441 Do I have to reimplement that logic into another method? :/ – Doug Smith Jul 28 '13 at 04:31
  • very interesting observation @Cezar.. what you said makes a lot of sense to me in light of some bugs i've faced in the past that I couldn't explain. Do you have some official documentation about this or some tutorial that highlights this fact? I gave you my +1 eitherway – abbood Jul 28 '13 at 06:51
  • @DougSmith you could implement that logic in a different method and call it both from `tableView:heightForRowAtIndexPath:` and `numberOfRowsInSection`. Even better, you could have that method be called when you initialize your `TableViewController` and store the information about the services the user hasn't logged into yet to a property in your `TableViewController`. – Cezar Jul 28 '13 at 12:14
  • @abbood sorry, I couldn't find any documentation that states this explicitly. But what I described above is essentially MVC and datasource/delegation at play. Having the `controller` ask the `tableView` for its number of rows is wrong, since the `tableView` relies on the `datasource` (which turns out to be the `controller` itself) to get this information from the `model`. – Cezar Jul 28 '13 at 12:21
  • Why is it not just considered a private helper method in this case, though? If you needed some action done repeatedly in a class you could sanction it off to a different method and call it, even though it's being called from the same class. How is asking the data source to perform that small amount of logic then return a number causing such trouble? Why doesn't it just return the value? – Doug Smith Jul 28 '13 at 15:42
  • @DougSmith this is where I fail you. Probably due to the way it has been implemented internally, which I don't actually have knowledge on. – Cezar Jul 28 '13 at 15:45
1

Instead of calling the numberOfRowsInSection: method from the tableView, you can do this:

if ([self tableView:tableView numberOfRowsInSection:indexPath.section] == 1) {
    standardHeight -= 2;
}

This will be safe because it only invocates your own code.

Andrew
  • 1,088
  • 10
  • 21