首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

iOS UITableView 高度代理崩潰:heightForRowAtIndexPath 中調用 cellForRowAtIndexPath 導致死循環

     編輯:程式設計綜合問答

問題現象

在 tableView:heightForRowAtIndexPath: 中呼叫 [self.tableView cellForRowAtIndexPath:indexPath] 取得 Cell 判斷高度,導致無限遞迴崩潰(heightForRow → cellForRow → 需要高度 → heightForRow...)。

錯誤程式碼


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];  // 致命錯誤!
    if ([cell.reuseIdentifier isEqualToString:@"EventWICellIdentifier"]) return 112;
    // ...
}

正確解法:根據資料模型決定高度

絕不在 heightForRow 中呼叫 cellForRow。高度應由資料模型(而非視圖)決定:

方案一:資料模型包含類型/高度資訊


// 模型
@interface EventItem : NSObject
@property (nonatomic, strong) NSString *type;  // "EventWI", "EventWOI", "PastEventWI", "PastEventWOI"
@property (nonatomic, assign) CGFloat height;   // 或根據型別計算
@end

// 代理
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    EventItem *item = self.dataSource[indexPath.row];
    if ([item.type isEqualToString:@"EventWI"] || [item.type isEqualToString:@"EventWOI"]) return 112;
    return 56;
}

方案二:使用自動行高 (iOS 8+ 推薦)


- (void)viewDidLoad {
    [super viewDidLoad];
    tableView.estimatedRowHeight = 80;  // 預估高度
    tableView.rowHeight = UITableViewAutomaticDimension;  // 自動計算
}

// Cell 內部使用 Auto Layout 完整約束,系統自動計算高度
// 完全不需要實作 heightForRowAtIndexPath

方案三:註冊 Cell 類別對應高度查表


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *reuseId = [self tableView:tableView cellForRowAtIndexPath:indexPath].reuseIdentifier;  // 仍錯誤!
    
    // 正確:從資料來源決定 reuseIdentifier
    EventItem *item = self.dataSource[indexPath.row];
    NSString *reuseId = [self reuseIdentifierForItem:item];
    
    static NSDictionary *heightMap = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        heightMap = @{
            @"PastEventWICellIdentifier": @56,
            @"PastEventWOICellIdentifier": @56,
            @"EventWICellIdentifier": @112,
            @"EventWOICellIdentifier": @112
        };
    });
    return [heightMap[reuseId] floatValue];
}

核心鐵律

  • heightForRowAtIndexPath 必須同步、快速、無副作用:TableView 滾動時頻繁呼叫,任何重邏輯/視圖建立都會卡頓。
  • 高度決策依賴資料模型,而非視圖實例。
  • 優先使用 AutomaticDimension + Auto Layout:零代碼維護高度,支援動態內容、多行文字、國際化。

現代最佳實踐

  1. Cell 使用 Auto Layout 完整約束(上下左右皆有約束)。
  2. tableView.estimatedRowHeight 設定合理預估值。
  3. tableView.rowHeight = UITableViewAutomaticDimension。
  4. 複雜動態高度才考慮手動實作 heightForRow,且嚴禁呼叫 cellForRow。

理解 TableView 佈局渲染流程與代理調用順序,是避免死循環、卡頓、崩潰的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved