83

I am trying to set the height of each row in the tableView to the height of the corresponding cell with this code:

override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
      var cell = tableView.cellForRowAtIndexPath(indexPath)
      return cell.frame.height
}

I get this error when initialising var cell :

Thread 1:EXC_BAD_ACCESS(code=2,address=0x306d2c)

Nagarjun
  • 6,557
  • 5
  • 33
  • 51
tim_yng
  • 2,591
  • 4
  • 18
  • 20
  • 1
    possible duplicate of [EXC\_BAD\_ACCESS in heightForRowAtIndexPath iOS](http://stackoverflow.com/questions/12652761/exc-bad-access-in-heightforrowatindexpath-ios) – Martin R Sep 02 '14 at 21:18
  • 4
    You must not call `cellForRowAtIndexPath` from within `heightForRowAtIndexPath`. The EXC_BAD_ACCESS is caused by a stack overflow caused by deep recursion. – Martin R Sep 02 '14 at 21:19
  • where should i call CellForRowAtIndexPath from? – tim_yng Sep 02 '14 at 21:23
  • 1
    `heightForRowAtIndexPath` must compute the cell's height from the data source, without loading the cell itself. – Martin R Sep 02 '14 at 21:25

9 Answers9

165

For setting row height there is separate method:

For Swift 3

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 100.0;//Choose your custom row height
}

Older Swift uses

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return 100.0;//Choose your custom row height
}

Otherwise you can set row height using:

self.tableView.rowHeight = 44.0

In ViewDidLoad.

Nagarjun
  • 6,557
  • 5
  • 33
  • 51
  • 1
    If you are using Swift 3.0 you must use this func: `func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat` – DoK Sep 30 '16 at 11:02
  • 1
    Hi Just tried to use this function and Xcode 9 beta 6 suggested override so correct signature is override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat – Nikhil Pandey Sep 11 '17 at 07:02
55

Put the default rowHeight in viewDidLoad or awakeFromNib. As pointed out by Martin R., you cannot call cellForRowAtIndexPath from heightForRowAtIndexPath

self.tableView.rowHeight = 44.0
Mundi
  • 79,884
  • 17
  • 117
  • 140
18
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        var height:CGFloat = CGFloat()
        if indexPath.row == 1 {
            height = 150
        }
        else {
            height = 50
        }
        return height
    }
Vishal Vaghasiya
  • 4,618
  • 3
  • 29
  • 40
14
yourTableView.rowHeight = UITableViewAutomaticDimension

Try this.

Prabhav
  • 969
  • 7
  • 8
6

As pointed out in comments, you cannot call cellForRowAtIndexPath inside heightForRowAtIndexPath.

What you can do is creating a template cell used to populate with your data and then compute its height. This cell doesn't participate to the table rendering, and it can be reused to calculate the height of each table cell.

Briefly, it consists of configuring the template cell with the data you want to display, make it resize accordingly to the content, and then read its height.

I have taken this code from a project I am working on - unfortunately it's in Objective C, I don't think you will have problems translating to swift

- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    static PostCommentCell *sizingCell = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sizingCell = [self.tblComments dequeueReusableCellWithIdentifier:POST_COMMENT_CELL_IDENTIFIER];
    });

    sizingCell.comment = self.comments[indexPath.row];
    [sizingCell setNeedsLayout];
    [sizingCell layoutIfNeeded];

    CGSize size = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    return size.height;
}
Antonio
  • 71,651
  • 11
  • 148
  • 165
  • This works but produces a lot of constraint errors when you scroll. – DarkLeafyGreen Nov 06 '14 at 12:52
  • That didn't happen in my case, and I've used autolayout. – Antonio Nov 06 '14 at 13:25
  • @Antonio Could you please help with how this can be translated into Swift? [Here](https://gist.github.com/floydpink/363aac55024f5c1b8650) is what I tried, but have been getting incorrect results. – Hari Pachuveetil Dec 17 '14 at 05:03
  • 1
    Hi think it would be better if you create a question for that - also expanding the "getting incorrect results" so to better understand what is not working properly. Don't forget to post the link here. – Antonio Dec 17 '14 at 10:59
3

Problem Cause:
The problem is that the cell has not been created yet. TableView first calculates the height for row and then populates the data for each row, so the rows array has not been created when heightForRow method gets called. So your app is trying to access a memory location which it does not have the permission to and therefor you get the EXC_BAD_ACCESS message.

How to achieve self sizing TableViewCell in UITableView:
Just set proper constraints for your views contained in TableViewCell's view in StoryBoard. Remember you shouldn't set height constraints to TableViewCell's root view, its height should be properly computable by the height of its subviews -- This is like what you do to set proper constraints for UIScrollView. This way your cells will get different heights according to their subviews. No additional action needed

Mehdi Ijadnazar
  • 4,532
  • 4
  • 35
  • 35
1

Make sure Your TableView Delegate are working as well. if not then in your story board or in .xib press and hold Control + right click on tableView drag and Drop to your Current ViewController. swift 2.0

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return 60.0;
}
Nagarjun
  • 6,557
  • 5
  • 33
  • 51
0

There is no way to call tableView.dequeueReusableCell from within tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath).

So you have to compute the height from the data. In my case that was not possible because I have a textView in the cell, which size I did not know.

So I come around with the following strategies:

  1. Do not use tableView.dequeueReusableCell. Just use an array of cells yo have under full control. If your cell is not too large in memory and you don't have too much rows, this is the simplest strategy.

  2. Use a dummy cell, configure it with your data and compute the size.

-4

Try code like this copy and paste in the class

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 100
}
Nagarjun
  • 6,557
  • 5
  • 33
  • 51