You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Objective-C:如何将ViewController数据传递给嵌套TableView的Cell

嘿,这个嵌套TableView展示问答列表的场景我之前做过好多次了,其实核心是把数据和UI职责分清楚,别让ViewController包揽所有逻辑,给你一步步拆解解决方案:

第一步:定义清晰的数据模型

先创建两个模型类,把问题和答案的数据结构封装起来,这样后续处理数据会非常顺手:

QuestionModel(问题模型)

// QuestionModel.h
#import <Foundation/Foundation.h>
@class AnswerModel;

@interface QuestionModel : NSObject
@property (nonatomic, copy) NSString *questionId;
@property (nonatomic, copy) NSString *questionContent;
@property (nonatomic, strong) NSArray<AnswerModel *> *answers;

// 从字典转模型的方法,根据你的接口返回格式调整
+ (instancetype)modelWithDictionary:(NSDictionary *)dict;
@end

// QuestionModel.m
#import "QuestionModel.h"
#import "AnswerModel.h"

@implementation QuestionModel
+ (instancetype)modelWithDictionary:(NSDictionary *)dict {
    QuestionModel *model = [[self alloc] init];
    model.questionId = dict[@"question_id"];
    model.questionContent = dict[@"question_content"];
    
    NSMutableArray *answerArr = [NSMutableArray array];
    for (NSDictionary *answerDict in dict[@"answers"]) {
        AnswerModel *answer = [AnswerModel modelWithDictionary:answerDict];
        [answerArr addObject:answer];
    }
    model.answers = answerArr;
    return model;
}
@end

AnswerModel(答案模型)

// AnswerModel.h
#import <Foundation/Foundation.h>

@interface AnswerModel : NSObject
@property (nonatomic, copy) NSString *answerId;
@property (nonatomic, copy) NSString *answerContent;

+ (instancetype)modelWithDictionary:(NSDictionary *)dict;
@end

// AnswerModel.m
#import "AnswerModel.h"

@implementation AnswerModel
+ (instancetype)modelWithDictionary:(NSDictionary *)dict {
    AnswerModel *model = [[self alloc] init];
    model.answerId = dict[@"answer_id"];
    model.answerContent = dict[@"answer_content"];
    return model;
}
@end

第二步:自定义外层TableViewCell,封装内层TableView逻辑

不要让ViewController管内层TableView的数据源/代理,把这部分职责交给外层Cell,实现解耦:

QuestionTableViewCell(外层Cell)

// QuestionTableViewCell.h
#import <UIKit/UIKit.h>
@class QuestionModel;

@interface QuestionTableViewCell : UITableViewCell
@property (nonatomic, strong) QuestionModel *questionModel;
@end

// QuestionTableViewCell.m
#import "QuestionTableViewCell.h"
#import "QuestionModel.h"
#import "AnswerModel.h"

@interface QuestionTableViewCell () <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) UITableView *innerTableView;
@property (nonatomic, strong) UILabel *questionLabel;
@end

@implementation QuestionTableViewCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self setupSubviews];
    }
    return self;
}

- (void)setupSubviews {
    // 1. 问题标题Label
    _questionLabel = [[UILabel alloc] init];
    _questionLabel.numberOfLines = 0;
    _questionLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium];
    [self.contentView addSubview:_questionLabel];
    
    // 2. 内层答案TableView
    _innerTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
    _innerTableView.dataSource = self;
    _innerTableView.delegate = self;
    _innerTableView.scrollEnabled = NO; // 禁用滚动,避免和外层冲突
    _innerTableView.rowHeight = UITableViewAutomaticDimension;
    _innerTableView.estimatedRowHeight = 44;
    _innerTableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
    [self.contentView addSubview:_innerTableView];
    
    // 3. 添加自动布局约束(用SnapKit或者系统约束都可以,这里用系统约束示例)
    _questionLabel.translatesAutoresizingMaskIntoConstraints = NO;
    _innerTableView.translatesAutoresizingMaskIntoConstraints = NO;
    
    [NSLayoutConstraint activateConstraints:@[
        [_questionLabel.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:16],
        [_questionLabel.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
        [_questionLabel.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
        
        [_innerTableView.topAnchor constraintEqualToAnchor:_questionLabel.bottomAnchor constant:12],
        [_innerTableView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
        [_innerTableView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
        [_innerTableView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-16]
    ]];
}

- (void)setQuestionModel:(QuestionModel *)questionModel {
    _questionModel = questionModel;
    self.questionLabel.text = questionModel.questionContent;
    [self.innerTableView reloadData]; // 数据更新后刷新内层TableView
}

#pragma mark - UITableViewDataSource & Delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.questionModel.answers.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellId = @"AnswerCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
        cell.textLabel.numberOfLines = 0;
        cell.textLabel.font = [UIFont systemFontOfSize:14];
    }
    AnswerModel *answer = self.questionModel.answers[indexPath.row];
    cell.textLabel.text = answer.answerContent;
    return cell;
}
@end

第三步:ViewController中的核心逻辑

ViewController只需要管好外层TableView的数据源和数据请求:

// YourViewController.m
#import "YourViewController.h"
#import "QuestionModel.h"
#import "QuestionTableViewCell.h"

@interface YourViewController () <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) UITableView *outerTableView;
@property (nonatomic, strong) NSArray<QuestionModel *> *questionsArray;
@end

@implementation YourViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setupOuterTableView];
    [self fetchDataFromServer];
}

- (void)setupOuterTableView {
    _outerTableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
    _outerTableView.dataSource = self;
    _outerTableView.delegate = self;
    _outerTableView.rowHeight = UITableViewAutomaticDimension;
    _outerTableView.estimatedRowHeight = 150; // 给一个预估高度,避免跳动
    [_outerTableView registerClass:[QuestionTableViewCell class] forCellReuseIdentifier:@"QuestionCell"];
    [self.view addSubview:_outerTableView];
}

- (void)fetchDataFromServer {
    // 这里替换成你的网络请求代码,比如用AFNetworking或者NSURLSession
    NSURL *url = [NSURL URLWithString:@"你的接口地址"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error) {
            NSLog(@"请求失败:%@", error.localizedDescription);
            return;
        }
        
        NSError *jsonError;
        NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
        if (jsonError) {
            NSLog(@"解析失败:%@", jsonError.localizedDescription);
            return;
        }
        
        // 解析数据成QuestionModel数组
        NSMutableArray *questions = [NSMutableArray array];
        for (NSDictionary *questionDict in responseDict[@"questions"]) {
            QuestionModel *model = [QuestionModel modelWithDictionary:questionDict];
            [questions addObject:model];
        }
        
        // 回到主线程刷新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            self.questionsArray = questions;
            [self.outerTableView reloadData];
        });
    }];
    [task resume];
}

#pragma mark - UITableViewDataSource & Delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.questionsArray.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    QuestionTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"QuestionCell" forIndexPath:indexPath];
    cell.questionModel = self.questionsArray[indexPath.row];
    return cell;
}
@end

几个关键的避坑点

  • 内层TableView一定要设置scrollEnabled = NO,否则会和外层TableView的滚动产生冲突,导致交互混乱
  • 内外层TableView都用UITableViewAutomaticDimension配合自动布局,实现高度的自适应,不用手动计算高度
  • 自定义Cell初始化时记得关闭translatesAutoresizingMaskIntoConstraints,否则自动布局会失效

内容的提问来源于stack exchange,提问作者MRizwan33

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:20:58