objective-c - tableview展開 - xcode uitableview




iOS中的EXC_BAD_ACCESS為heightForRowAtIndexPath (4)

cellForRowAtIndexPath之前調用tableView heightForRowAtIndexPath ,在顯示單元格之前,需要首先計算高度。

你應該從你的數據源獲取text ,而不是從cell

我正在開發一個應用程序,我有一個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]; ,我不知道為什麼。 我試圖建立乾淨並重置模擬器,但都沒有工作。 任何想法為什麼會這樣?


在這種情況下,你應該調用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異常。


我試圖重現這個問題。 事實證明,調用cellForRowAtIndexPath: inside 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的高度。 您應該從數據源獲取文本。


迅速:

使用它來了解表的加載時間:

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!
             }

}




uitableview