EXC_BAD_ACCESS in heightForRowAtIndexPath iOS

我正在一个应用程序,我有一个自定义的UITableViewCell的子类。 我想根据里面的文本使单元格的高度dynamic化。 我尝试在我的heightForRowAtIndexPath方法中做到这一点。 但是我有一些问题,下面的代码会导致EXC_BAD_ACCESS(code = 2 address = 0xb7ffffcc)的错误。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { PostCell *cell = (PostCell *)[tableView cellForRowAtIndexPath:indexPath]; CGSize postTextSize; if (![cell.postText.text isEqualToString:@""]) { postTextSize = [cell.postText.text sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:CGSizeMake(cell.postText.frame.size.width, 200)]; } else { postTextSize = CGSizeMake(cell.postText.frame.size.width, 40); } return postTextSize.height + cell.userName.frame.size.height + 10; } 

如果我反而有:

 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 100; } 

有用。

这似乎是崩溃在这一行上: PostCell *cell = (PostCell *)[tableView cellForRowAtIndexPath:indexPath]; ,我不知道为什么。 我试图build立清洁和重置模拟器,但都没有工作。 任何想法为什么发生这种情况?

我试图重现这个问题。 事实certificate,调用cellForRowAtIndexPath:heightForRowAtIndexPath导致heightForRowAtIndexPathrecursion调用。 下面是三个recursion步骤之后的栈回溯的摘录:

 frame #0: 0x000042d0 DocInteraction`-[DITableViewController tableView:heightForRowAtIndexPath:] + 48 at DITableViewController.m:262 frame #1: 0x0054f688 UIKit`-[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 3437 frame #2: 0x0055040f UIKit`-[UITableViewRowData(UITableViewRowDataPrivate) _ensureSectionOffsetIsValidForSection:] + 144 frame #3: 0x00551889 UIKit`-[UITableViewRowData numberOfRows] + 137 frame #4: 0x00553dac UIKit`-[UITableViewRowData globalRowsInRect:] + 42 frame #5: 0x003f82eb UIKit`-[UITableView(_UITableViewPrivate) _visibleGlobalRowsInRect:] + 177 frame #6: 0x004001e6 UIKit`-[UITableView cellForRowAtIndexPath:] + 113 frame #7: 0x000042f2 DocInteraction`-[DITableViewController tableView:heightForRowAtIndexPath:] + 82 at DITableViewController.m:262 frame #8: 0x0054f688 UIKit`-[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 3437 frame #9: 0x0055040f UIKit`-[UITableViewRowData(UITableViewRowDataPrivate) _ensureSectionOffsetIsValidForSection:] + 144 frame #10: 0x00551889 UIKit`-[UITableViewRowData numberOfRows] + 137 frame #11: 0x00553dac UIKit`-[UITableViewRowData globalRowsInRect:] + 42 frame #12: 0x003f82eb UIKit`-[UITableView(_UITableViewPrivate) _visibleGlobalRowsInRect:] + 177 frame #13: 0x004001e6 UIKit`-[UITableView cellForRowAtIndexPath:] + 113 frame #14: 0x000042f2 DocInteraction`-[DITableViewController tableView:heightForRowAtIndexPath:] + 82 at DITableViewController.m:262 frame #15: 0x0054f688 UIKit`-[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 3437 frame #16: 0x0055040f UIKit`-[UITableViewRowData(UITableViewRowDataPrivate) _ensureSectionOffsetIsValidForSection:] + 144 frame #17: 0x00551889 UIKit`-[UITableViewRowData numberOfRows] + 137 frame #18: 0x003ff66d UIKit`-[UITableView noteNumberOfRowsChanged] + 119 frame #19: 0x003ff167 UIKit`-[UITableView reloadData] + 764 

最后程序崩溃了。 在我的模拟器上,当后面的轨迹深度大约是57000时,会发生这种情况。


旧的答案 (没有错,但不解释EXC_BAD_ACCESS):

问题是这样的

 [tableView cellForRowAtIndexPath:indexPath] 

对于当前不可见的行返回nil 。 表视图仅分配显示当前可见行所需的单元。 滚动表格视图时,单元格将被重新使用。

但是,在显示任何行之前,将为表视图的所有单元调用heightForRowAtIndexPath

因此,您不应该从表视图单元格中获取文本来计算heightForRowAtIndexPath的高度。 您应该从数据源中获取文本。

tableView heightForRowAtIndexPathcellForRowAtIndexPath之前调用,在显示单元格之前,需要先计算高度。

你应该从你的数据源,而不是从cell获取text

我遇到过类似的问题,只是为了分享我现在做的工作,对我来说很好

 CGFloat mycell_height; - (void)viewDidLoad { [super viewDidLoad]; UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCell"]; mycell_height = cell.frame.size.height; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return mycell_height; //assuming all cells are the same } 

希望这有助于任何寻找这个和新的像我这样的iOS编程的人:-)

在这种情况下,您应该调用UITableViewDataSource方法获取单元格的indexPath而不是cellForRowAtIndexPath:UITableView的方法,因为此时tableView:heightForRowAtIndexPath:第一次调用时,tableView中没有任何单元格。

 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath *)indexPath { PostCell *cell = (PostCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath]; CGSize postTextSize; if (![cell.postText.text isEqualToString:@""]) { postTextSize = [cell.postText.text sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:CGSizeMake(cell.postText.frame.size.width, 200)]; } else { postTextSize = CGSizeMake(cell.postText.frame.size.width, 40); } return postTextSize.height + cell.userName.frame.size.height + 10; } 

它的工作原理并不会导致EXC_BAD_ACCESSexception。

迅速:

使用这个来知道表何时加载:

 extension UITableView { func reloadData(completion: ()->()) { UIView.animateWithDuration(0, animations: { self.reloadData() }) { _ in completion() } } } 

创build一个布尔值

 var tables_loaded = Bool(false) 

然后在viewDidLoad中:

 tableView.reloadData { tables_loaded = true // call functions or other stuff regarding table manipulation. // tableView.beginUpdates() // tableView.endUpdates() } 

然后进入

 override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { if tables_loaded { let cell = tableView.cellForRowAtIndexPath(indexPath) // Do your magic here! } }