How to discover why heightForRowAtIndexPath is crashing - ios

I am not a full-time iOS dev and I'm trying to return the cell at the current indexPath but this is crashing and I am not sure exactly why. I maintain the height dynamically on the cell. My cell is a custom UITableViewCell called MICell and I have a property called height which is dynamically calculated in the updateCell method.
#import "MICell.h"
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
MICell *cell = (MICell *)[self tableView:tableView cellForRowAtIndexPath:indexPath];
// hardcoded to 200.0f but still crashing
NSLog(#"here is my height; %f",cell.height);
return 200.0f;
}
Edit 1
As a workaround, I am able to make an instance variable and just write the current cell height which is then accessed in heightForRowAtIndexPath, like the following. I do feel that this is potentially making assumptions that I'm not fully comfortable with:
#interface ListViewController (){
NSMutableArray *_data;
CGFloat _currentCellHeight;
}
...
-(MICell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MICell";
MICell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
// Configure the cell here ...
NSDictionary *tmp=[_data objectAtIndex:indexPath.row];
[cell updateCell:tmp];
_currentCellHeight=cell.height;
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return _currentCellHeight;
}
Edit 2
Here's a reference to this exact technique. How to get the cell object in tableView:(UITableView *)tableView heightForRowAtIndexPath function?
Edit #3
The above code works fine - there was an issue with IB connections.

It's because you're causing an infinite cycle. You cannot call:
[self tableView:tableView cellForRowAtIndexPath:indexPath];
In height for row at index path.
[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
will cause issues when called from height for row at index path. You must call tableView dequeueReusableCellWithIdentifier: without the forIndexPath. You should probably create a configureWithCell:(YourCellClass *)cell method separate from these so you can just configure your cell after properly dequeueing/allocating it.
Also, you do not grab the height from the cell as you're doing above (unless you're assigning a height property with some weird forwarding stuff that breaks class containment... which you shouldn't do either). Use the following for dynamic cell heights via auto layout:
CGFloat cellHeight = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
Something like the following below should do the trick:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyCellClass *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([MyCellClass class]) forIndexPath:indexPath];
[self configureMyCell:cell forIndexPath:indexPath];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyCellClass * cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([MyCellClass class])];
[self configureMyCell:cell forIndexPath:indexPath];
CGFloat cellHeight = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return cellHeight;
}

In ios, the height of the cell is calculated in heightForRowAtIndexPath. What you are trying to do is to get height of the cell inside heightForRowAtIndexPath. It is definitely not the way to do it. To have dynamic height, calculate the height inside heightForRowAtIndexPath using the features/values you might need and return that height.
Bottom line is you cannot call cell.height inside heightForRowAtIndexPath.
Edit 1:
To help you deal with the dynamic heights in cell, please look at this tutorial. It might help you understand the issue : Dynamic Cell
Just go straight to the tableView delegates method to get an understanding of how to proceed.

Related

Change height of row in UITableView

I have created a simple UITableView with a prototype cell and I have to enlarge the height of row. Unfortunately, I cannot achieve that. I just put the custom size of height for the prototype cell in Interface Builder (Xcode) and put method in ViewController:
-(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 200.0;
}
And cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
AlbumCell *cell = [tableView dequeueReusableCellWithIdentifier:#"albumCellID"];
if (cell == nil) {
cell = [[AlbumCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"albumCellID"];
}
cell.albumTitle.text = [tableData objectAtIndex:indexPath.row];
return cell;
}
Simulator returns my table with still small height for rows (ca. 40 px). How can I enlarge the height of a row?

How to change Custom Cell's UILabel Text?

I have a table view with a custom protoype cell and the cell has 3 different labels on it. How do I get access to these labels? I need to change their texts. I've searched around everywhere and haven't found something that helps me in this case. I have the below code:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"basicCell" forIndexPath:indexPath];
//change cell's 3 labels' text here
return cell;
}
How can I access the above cell's 3 different labels that it has?
You need to make a class that is a subclass of UITableViewCell, and set the custom cell's class to the class you made. Then you want to link the labels using IBOutlets in the cell to the subclass you made.
Finally, in -tableView:cellForRowAtIndexPath:, you should cast the cell to your new subclass so you get access to those IBOutlets. Assuming your outlets are named someLabelOutlet1, someLabelOutlet2, and someLabelOutlet3, do the following after you finished subclassing.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
SomeTableViewCellSubclass *cell = (SomeTableViewCellSubclass *)[tableView dequeueReusableCellWithIdentifier:#"basicCell" forIndexPath:indexPath];
cell.someLabelOutlet1.text = #"sometext"
cell.someLabelOutlet2.text = #"sometext"
cell.someLabelOutlet3.text = #"sometext"
return cell;
}
In cellForRowAtIndexPath, you can access these labels
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell =[tableView dequeueReusableCellWithIdentifier:#"CustomCell"];
if (!cell) {
[tableView registerNib:[UINib nibWithNibName:#"CustomCell" bundle:nil] forCellReuseIdentifier:#"CustomCell"];
cell = [tableView dequeueReusableCellWithIdentifier:#"CustomCell"];
// set common properties here
cell.lbl1.textColor=[UIColor whiteColor];
cell.lbl1.backgroundColor=[UIColor redColor];
cell.lbl1.font=[UIFont fontWithName:#"Verdana" size:16.0];
}
cell.lbl1.text=#"lbl1Txt";
cell.lbl2.text=#"lbl2Txt";
cell.lbl3.text=#"lbl3Txt";
return cell;
}

How to Set a Space between Tableview Cell in iOS?

I am newbie in iOS development and i know this question is asked many times but i confuse for it. I want to know how to set a space between UITableview cell in section.In my app UITableview contain two section first section contain only one data value so not any problem. but my second section contain 5 to 7 data value But not a space between them how to set a space in footer between second section cell in UITableview.
OK so you have two methods for sections
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
and
-(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
but neither serve the purpose of putting space between cells in a single section.
For my money there are two options... first and most complicated / hacky
in - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView you could return the count of the cells in the second section and in cellForRowAtIndexPath if (section == 0) put the data in the usual way... else you can pull the info out of the array or whatever using [theArray objectAtIndex:indexPath.section] instead.
(much simpler, and better practice).. Create a UITableViewCell subclass and use that in your cellForRowAtIndexPath like so
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
static NSString *MyCellIdentifier = #"MyCustomCell";
switch (indexPath.section) {
case 0:
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// setup your 1st section cells here
return cell;
}
default:
{
MYTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyCellIdentifier];
if (!cell)
cell = [[MYTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyCellIdentifier];
// all other layout code here if indexPath.row == 0 etc.
return cell;
}
}
in your custom cell .m you can set
-(void)layoutSubviews
{
[super layoutSubviews];
self.imageView.frame = CGRectMake(0,0,0,0); // lay them out at the top / middle / wherever in your cell
self.textLabel.frame = CGRectMake(0,0,0,0); // which will allow for some space at the bottom / edges
}
then finally use
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.section == 0)
return THE_CELL_HEIGHT;
else
return THE_CELL_HEIGHT + PADDING;
}
This way you can set padding in the cell itself, which is cleaner and reusable. If you want different colours to mark the spacing, you should create UIViews in the custom UITableViewCell subclass method
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
and add them using [self.contentView addSubView:someView]; you can always set the backgroundColor of a cell to [UIColor clearColor]; if you have an image / content behind the tableView

How to resize cell height and the row height in ios

I have a UITableView that display a program name and the DJ name. For some programmes, there are no any DJs. So I created a custom UITableViewCell by putting 2 UILabels. Middle of the UITableViewCell displays the programme name and bottom UILabel displays the DJ name. To display both programme and the DJ name I have to set the cell size and UITableViewCell size as 147. But when DJ is not available I want to hide that bottom label and resize the cell and row height to 70. so how should I do this ?
I am checking if this DJ is null or not inside my cellForRowAtIndexPath method.
How I can resize the cell, and row height ?
Thanks for the help.
You need to use the following delegate:
-(CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*) indexPath {
if(...){
return 147.0f; //or whatever
}
else{
return 70.f;
}
}
Add NSIndexPath below #implementation
NSIndexPath *selectedCellIndexPath;
Add Both of these methods.
// And in the implementation file:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
selectedCellIndexPath = indexPath;
// Forces the table view to call heightForRowAtIndexPath
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// Note: Some operations like calling [tableView cellForRowAtIndexPath:indexPath]
// will call heightForRow and thus create a stack overflow
if(selectedCellIndexPath != nil
&& [selectedCellIndexPath compare:indexPath] == NSOrderedSame)
return 338;
return 64;
}
You have 2 types of cell. With height of 147 and 70 pixels.
1) As Anoop Vaidya said you should set cell height by checking "DJ is null or not".
2) To avoid reusing wrong cell template, you should use 2 types of cellIdentifier:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = nil;
if (check DJ is nil or not) {
CellIdentifier = #"CellWithHeight_147";
} else {
CellIdentifier = #"CellWithHeight_70";
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
}
...
return cell;
}

Reduced cell in grouped UITableview

I am adding one more section to the existing tableView and getting this:
my new cell is reduced by height. Appropriate methods:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
return cells[indexPath.section][indexPath.row];
}
- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
if ([headers[section] isKindOfClass:[UIView class]])
return [headers[section] frame].size.height;
return 10.0f;
}
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
if ([headers[section] isKindOfClass:[UIView class]])
return headers[section];
return nil;
}
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = cells[indexPath.section][indexPath.row];
if (cell == clientXibCell) return 100.0f;
if (cell == agencyXibCell) return 145.0f;
return 46.0f;
}
I can't understand what I need to do to fix this. Any ideas where the source of issue can be?
Update
I am now sure that predefining custom cell visual interface making this trouble.
supervisorCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil];
bgView = [[UIImageView alloc] initWithFrame:supervisorCell.backgroundView.frame];
[bgView setImage:stretchableImageByHorizontal([UIImage imageNamed:#"cell_bgd_bottom"])];
[supervisorCell setBackgroundView:bgView];
bgView = [[UIImageView alloc] initWithFrame:supervisorCell.backgroundView.frame];
[bgView setImage:stretchableImageByHorizontal([UIImage imageNamed:#"cell_bgd_bottom_active"])];
[supervisorCell setSelectedBackgroundView:bgView];
When I am uncommenting everything except first statement of creating the cell, everything works fine except custom appearance of cell. What do I need to change in this simple code to fix this?
The height of your cells are controlled by the heightForRowAtIndexPath:. Taking a look on your code, it seems that this method is always returning 46.
Your two ifs are comparing pointers, i. e., instancies of your cells. It means that of all your cells, one will have the height 100, one 145 and all others 46.f.
I think what are you trying to accomplish is set this height for all cells of the same kind, so you should change your heightForRowAtIndexPath: method, like below:
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ( [cell isKindOfClass:[YourCustomCell1 class]] ) return 100.0f;
if ( [cell isKindOfClass:[YourCustomCell2 class]] ) return 145.0f;
return 46.0f;
}
Ps1: Change YourCustomCell class for your own classes. If you don't have subclasses, try to set tags or something like that to differentiate them.
Ps2: always use tableview's method cellForRowAtIndexPath to get the reference of the cell by the indexPath.

Resources