为什么tableView reloadData不调用cellForRowAtIndexPath

时间:2016-12-08 16:37:01

标签: ios objective-c iphone uitableview uiviewcontroller

我有两个ViewControllers:

带有“推”按钮的UIViewController,另一个带有tableView的UIViewController。

PushAction

- (IBAction)pushViewController:(id)sender {
    NSArray *dataArr = @[@1,@2,@3,@4,@5];

    NextViewController *nextViewController = [[NextViewController alloc] init];
    [nextViewController setDataAndReload:dataArr];
    [self.navigationController pushViewController:nextViewController animated:YES];
}

NextViewController.h

@interface NextViewController : UIViewController

- (void)setDataAndReload:(NSArray *)dataArr;

@end

NextViewController.m

#import "NextViewController.h"

@interface NextViewController () <UITableViewDelegate, UITableViewDataSource>

@property (nonatomic, strong) UITableView *tableView;

@end

@implementation NextViewController {
    NSMutableArray *_arr;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.view addSubview:self.tableView];
    [self.tableView reloadData];
 }

- (void)setDataAndReload:(NSArray *)dataArr {
    //[self loadViewIfNeeded];
    _arr = [dataArr mutableCopy];
    [self.tableView reloadData];
}

 #pragma mark - data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return _arr.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellIdentifier = @"CellIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }

    cell.textLabel.text = [NSString stringWithFormat:@"Cell %@", _arr[indexPath.row]];

    return cell;
}

#pragma mark - delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [_arr removeObjectAtIndex:indexPath.row];
    [self.tableView reloadData];
}

- (UITableView *)tableView {
    if (!_tableView) {
        _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
        _tableView.delegate = self;
        _tableView.dataSource = self;
        _tableView.backgroundColor = [UIColor whiteColor];
    }
    return _tableView;
}

TableView is visible

您注意到我在将tableView添加到任何视图之前调用了[self.tableView reloadData]

然后,当我选择tableView上的任何单元格(选择后将调用[self.tableView reloadData])时,tableView不会按预期重新加载。

通过向tableView的dataSource方法添加一些断点进行调试后,我发现numberOfRowsInSection:已被正确调用,但cellForRowAtIndexPath已调用而不是

然后我认为导致问题的原因可能是在我将tableView添加到viewController的视图之前setDataAndReload:调用[self.tableView reloadData]。所以我添加了[self loadViewIfNeeded]并且cellForRowAtIndexPath: 被正确调用。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [_arr removeObjectAtIndex:indexPath.row];
    [self.tableView reloadData];
}

因此,我想知道为什么在tableView的委托方法 cellForRowAtIndexPath[self.tableView reloadData] 之后无法调用didSelectRowAtIndexPath:

3 个答案:

答案 0 :(得分:1)

我找到了cellForRowAtIndexPath

之后无法调用[self.tableView reloadData]的原因

当我在[self.tableView reloadData]中调用setDataAndReload:时,它将调用tableView的惰性方法。

当我使用self.view.bounds初始化表视图时,在第一次调用setDataAndReload:时,视图尚未加载。所以它将加载如下(虽然tableView尚未创建并返回) :

loadView - &gt; viewDidLoad - &gt; [self.view addSubview:self.tableView] - &gt;懒惰的方法agian

- &GT;返回第二个tableView

- &GT; self.tableView是第二个tableView

- &GT;第二个tableView被添加到superView

- &GT;返回第一个tableView

- &GT; self.tableView是第一个tableView

因此,self.tableView最终指向的tableView从未添加到superView!

答案 1 :(得分:0)

当你设置你的- (void)setDataAndReload:(NSArray *)dataArr时,就像你悲伤一样,tableView甚至没有被初始化,也不是视图层次结构的一部分。所以我建议将方法重命名为- (void)setData:(NSArray *)dataArr并仅在viewDidLoad重新加载tableView。

所以这是您更新的代码:

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view addSubview:self.tableView];
    [self.tableView reloadData];
 }

- (void)setDataAndReload:(NSArray *)dataArr {
    _arr = [dataArr mutableCopy];
}

答案 2 :(得分:0)

didSelectRowAtIndexPath中,如果tableView没有重新加载数据。你应该检查调用者self.tableView,它一定有问题。并且您会发现self.tableView已将其指针更改为新的tableView。然后你应该检查你的getter方法。在getter方法中,如果我们想要使用一些属性,我们必须要小心。因为有时我们可能不止一次调用getter,为什么?在您的示例中,您尝试从self.view获取边界,self.view将向-(void)loadView;发送消息,这是VC的生命周期方法,-(void)loadView将发送消息到-(void)viewDidLoad;现在,-(void)viewDidLoad再次呼叫self.tableView。 Fortuantely,它不会导致循环。