我正在开发一个应用程序,我有一个UITableViewCell的自定义子类。我想根据里面的文字使单元格的高度动态化。我尝试在我的heightForRowAtIndexPath方法中做到这一点。但我有一些问题,以下代码导致和EXC_BAD_ACCESS(代码= 2地址= 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];
,我不知道为什么。我试图建立干净并重置模拟器,但都没有工作。任何想法为什么会这样?
答案 0 :(得分:53)
我试图重现这个问题。事实证明,在cellForRowAtIndexPath:
内调用heightForRowAtIndexPath
会导致heightForRowAtIndexPath
递归调用。以下是3个递归步骤之后的堆栈回溯的摘录:
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
中的高度。您应该从数据源获取文本。
答案 1 :(得分:7)
tableView heightForRowAtIndexPath
之前调用 cellForRowAtIndexPath
,在显示单元格之前,需要先计算高度。
您应该从数据源获取text
,而不是cell
答案 2 :(得分:2)
我遇到了类似的问题并且遇到过,只是为了分享我现在做的对我来说很有效的事情
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编程新手的人: - )
答案 3 :(得分:0)
在这种情况下,你应该调用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_ACCESS异常。
答案 4 :(得分:-1)
(SWIFT):
使用它来了解表格的加载时间:
extension UITableView {
func reloadData(completion: ()->()) {
UIView.animateWithDuration(0, animations: { self.reloadData() })
{ _ in completion() }
}
}
创建一个布尔值
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!
}
}