Reputation: 153
I have two ViewControllers:
An UIViewController with a "push" button, Another UIViewController with a tableView.
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;
}
You have noticed that I called [self.tableView reloadData]
before tableView was added to any view
Then, when I select any cell on the tableView, which will call [self.tableView reloadData]
after selected, the tableView doesn't reload as expected.
After debugging with adding some breakpoints to tableView's dataSource methods, I found that numberOfRowsInSection:
has been called correctly, but cellForRowAtIndexPath
has not been called.
Then I think what cause the issue maybe is that setDataAndReload:
call [self.tableView reloadData]
before I added the tableView to viewController's view. So I added [self loadViewIfNeeded]
and cellForRowAtIndexPath:
was called correctly.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[_arr removeObjectAtIndex:indexPath.row];
[self.tableView reloadData];
}
Thus, I wonder why cellForRowAtIndexPath
can not be called after [self.tableView reloadData]
in the tableView's delegate method didSelectRowAtIndexPath:
.
Upvotes: 0
Views: 925
Reputation: 419
In didSelectRowAtIndexPath
, if the tableView doesn't reloadData.You should check the caller self.tableView
, it must have some problem. And you will find the self.tableView
has change its pointer to a new tableView
. Then you should check your getter method. In getter method, if we want to use some properties, we must be careful.Because sometimes we may be call the getter more than once,Why?. In your example, you try to get the bounds from self.view
, and self.view
will send message to -(void)loadView;
,which is the lifecycle method of VC, and -(void)loadView
will send message to -(void)viewDidLoad;
Now, -(void)viewDidLoad
call the self.tableView
again. Fortuantely, it doesn't cause a loop.
Upvotes: 0
Reputation: 153
I have found what cause cellForRowAtIndexPath
can not be called after [self.tableView reloadData]
When I call [self.tableView reloadData]
in setDataAndReload:
It will call the lazy method of tableView.
As I used self.view.bounds
to initialize the table view, an at the first time setDataAndReload:
was called, the view has not been loaded. So it will load as below (while the tableView has not been created and returned)
:
loadView
-> viewDidLoad
-> [self.view addSubview:self.tableView]
-> lazy method agian
-> return second tableView
-> self.tableView
is the second tableView
-> second tableView is added to superView
-> return first tableView
-> self.tableView
is the first tableView
Thus, the tableView that self.tableView
finally pointed to, was never added to a superView!
Upvotes: 1
Reputation: 6151
When you are setting your in - (void)setDataAndReload:(NSArray *)dataArr
, like you sad, the tableView
is not even initialised and not part of the view hierarchy. so i would recommend to rename the method to - (void)setData:(NSArray *)dataArr
and reload the tableView in viewDidLoad
only.
So here is your the updated code:
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.tableView];
[self.tableView reloadData];
}
- (void)setDataAndReload:(NSArray *)dataArr {
_arr = [dataArr mutableCopy];
}
Upvotes: 0