Reputation: 9157
I have a table view with only one cell. When I call a method, I try to refresh it and the text label's text should change. However it does not, it only changes if the view re appears.
I have added NSLog()
in many places and the correct methods and conditions are called
I have tried a few things:
reloadData
setNeedsDisplay
setNeedsLayout
reloadCell
reloadRowsAtIndexPaths: withRowAnimation:
But nothing has worked, I know it is not a problem with my UITableViewDataSource
code because it is properly getting called.
This is the most appropriate code I can give you:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
tableView.scrollEnabled = NO;
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier: @"cell"];
if (cell) {
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if ([[TravelLogViewController locationArray] count]) {
NSDictionary *flight = [NSDictionary dictionaryWithObjectsAndKeys:[[TravelLogViewController locationArray] lastObject], @"name", [[TravelLogViewController dateArray] lastObject], @"date", [[TravelLogViewController milesGainedIndex] lastObject], @"miles", nil];
cell.detailTextLabel.textColor = [UIColor blackColor];
cell.textLabel.numberOfLines = 2;
cell.detailTextLabel.numberOfLines = 2;
cell.textLabel.font = [UIFont fontWithName:@"Avenir" size: 14.0];
cell.detailTextLabel.font = [UIFont fontWithName:@"Avenir" size: 12.0];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.text = [flight objectForKey: @"name"];
cell.detailTextLabel.text = [NSString stringWithFormat:@"Flight Date: %@, Miles Gained: %.1f", [flight objectForKey: @"date"], [[flight objectForKey: @"miles"] doubleValue]];
cell.backgroundColor = [UIColor colorWithWhite:0.92 alpha:1];
// cell.backgroundColor = [UIColor clearColor];
}
else {
// This gets called when I want it to, but the textLabel text or detailTextLabel text is not changed
cell.detailTextLabel.text = nil;
cell.textLabel.text = nil;
cell.textLabel.font = [UIFont fontWithName:@"Arial Rounded MT Bold" size: 18.0];
cell.textLabel.text = @"\n\n No Flights";
}
}
return cell;
}
UPDATE:
I am using ARC, and I have found that the table view is nil at the time I try to update the cell, but I have revised my cell and have no clue why!?
I am not nilling or releasing my table view anywhere, it should still be allocated
By the way I have a tab bar controller
UPDATE:
I have started a bounty now, its over a week later and I really feel this question needs some more attention and answers, I have checked my code multiple times and I cannot see why the table view is not updating / is nil
.
UPDATE:
Ok, I have forgot to mention that the user can swipe to delete the cell. When he does, it does not actually delete the cell, it just changes its text (that is the part it is not updating). I put logs in viewDidLoad
and viewDidAppear
and table view appears to be valid, once the user swipes to delete... here is my code:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
TravelLogViewController *travel = [[TravelLogViewController alloc] init];
[travel manuallyDeleteTopCellData]; // Deletes some data in other view controller and calls the method `proceedWithDeletion`
}
}
- (void)proceedWithDeletion {
// Method is called from another view controller
NSLog(@"%@", mostRecentFlight.description); // NIL HERE
[mostRecentFlight reloadData];
[mostRecentFlight setNeedsDisplay];
[mostRecentFlight setNeedsLayout];
}
TravelLogViewController
- (void)manuallyDeleteTopCell {
[TheMileIndexViewController deductDesiredMilesToIndex: [[milesGainedIndex lastObject] floatValue]];
[locationArray removeLastObject];
[milesGainedIndex removeLastObject];
[dateArray removeLastObject];
MenuMileIndexViewController *menu = [[MenuMileIndexViewController alloc] init];
[menu proceedWithDeletion];
}
So to sum up, one the view loads/appears, the table view is valid. When the user swipes to delete, it does not actually delete the row it just calls another view controller called TravelLogViewController
method called manuallyDeleteTopCellData
where it deletes some data, that method then calls another method in my original view controller called proceedWithDeletion
where it is supposed to reload the table view, but doesn't (the problem). The reason for this is because in proceedWithDeletion
the table view is nil, but why!?
Upvotes: 2
Views: 1125
Reputation: 3326
In your implementation of manuallyDeleteTopCell
in TravelLogViewController
you instantiate a new MenuMileIndexViewController
at this point:
MenuMileIndexViewController *menu = [[MenuMileIndexViewController alloc] init];
[menu proceedWithDeletion];
This is a different controller and is neither properly initialized nor responsible for the view on the screen. In particular, it does not have the same mostRecentFlight
property. In order for the TravelLogViewController
to call your original controller, you need to pass it as a parameter to manuallyDeleteTopCell
and call that one back, e.g. as follows
- (void)manuallyDeleteTopCell:(MenuMileIndexViewController *)origin {
[TheMileIndexViewController deductDesiredMilesToIndex: [[milesGainedIndex lastObject] floatValue]];
[locationArray removeLastObject];
[milesGainedIndex removeLastObject];
[dateArray removeLastObject];
[origin proceedWithDeletion];
}
And rewrite the calling code as follows:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
TravelLogViewController *travel = [[TravelLogViewController alloc] init];
[travel manuallyDeleteTopCellData:self];
}
Former suggestions:
Make sure that you have set the outlet properly in the Interface Builder. You say in a comment that you did this, but at another point you say that you are using a tab bar controller. Make sure you are setting the outlet on a regular view controller (i.e., a subclass of UIViewController
) that is currently visible and contained in the viewControllers
property of the UITabBarController
instance you are using. Do not subclass UITabBarController
(see the Apple documentation which explicitly prohibits it). [CHECKED]
Implement the viewDidLoad
method of the regular view controller and NSLog
the self.tableView
property to verify it is non-nil
at the time this method is called. [CHECKED]
Write a @synthesize mostRecentFlight = _mostRecentFlight;
statement in the @implementation
of TravelLogViewController
and set a breakpoint on the property in the @interface
. Alternatively, manually implement the setMostRecentFlight:
method for the mostRecentFlight
property and set a breakpoint inside this method. This breakpoint will trigger if the setter is called which will help you find the time the property is set to nil
.
Assuming the property is non-nil in the viewDidLoad
method in step 2, look at the address of the object (the beginning of the description which says (UITableView *) $1 = 0xXXXXXXXX
with 0xXXXXXXXX
being the address). Set a breakpoint where you want to use the object later in your code (when the property is nil). Type at the debugger po 0xXXXXXXXX
(with the appropriate address from above). What is the response you get?
Upvotes: 1
Reputation: 6489
This code could be the source of your problem:
MenuMileIndexViewController *menu = [[MenuMileIndexViewController alloc] init];
[menu proceedWithDeletion];
You're creating a brand new MenuMileIndexViewController
, not accessing the already existing instance, which is what I presume you want to do. This new instance won't have access to the original table view stored in mostRecentFlight
. Inside -manuallyDeleteTopCell
, you'll need a reference to the calling MenuMileIndexViewController
instance.
It might be as simple as passing self
to -manuallyDeleteTopCellData
and using that variable to subsequently call -proceedWithDeletion
on. For example:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
TravelLogViewController *travel = [[TravelLogViewController alloc] init];
[travel manuallyDeleteTopCellData:self];
}
}
- (void)manuallyDeleteTopCell:(id)sender {
[TheMileIndexViewController deductDesiredMilesToIndex: [[milesGainedIndex lastObject] floatValue]];
[locationArray removeLastObject];
[milesGainedIndex removeLastObject];
[dateArray removeLastObject];
// MenuMileIndexViewController *menu = [[MenuMileIndexViewController alloc] init];
[sender proceedWithDeletion];
}
Upvotes: 1
Reputation: 1780
I'd like to notice. if you are working with storyboard you don't need to alloc your cell. This code is enough:
- (UITableViewCell *)tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath)indexPath
{
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:@"PlayerCell"];
Player *player = [self.players objectAtIndex:indexPath.row];
cell.textLabel.text = player.name;
cell.detailTextLabel.text = player.game;
return cell;
}
Upvotes: 0
Reputation: 5665
I can pretty much confirm that the problem is not in the areas you're looking or describing.
I have created a sample project from scratch, very minimally just putting a UITableView
and a UIButton
that triggers a [table reloadData]
and flips a boolean value:
BOOL toggle = NO;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier: @"cell"];
if (cell) {
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if (toggle )
{
NSDictionary *flight = @{@"name" : @"Bob",
@"date" : @"Yesterday",
@"miles" : @"3" };
cell.textLabel.text = [flight objectForKey: @"name"];
cell.textLabel.numberOfLines = 2;
cell.detailTextLabel.numberOfLines = 2;
cell.detailTextLabel.textColor = [UIColor blackColor];
cell.detailTextLabel.text = [NSString stringWithFormat:@"Flight Date: %@, Miles Gained: %.1f", [flight objectForKey: @"date"], [[flight objectForKey: @"miles"] doubleValue]];
} else {
cell.textLabel.text = @"blank label";
cell.detailTextLabel.text = @"blank detail";
}
}
return cell;
}
- (IBAction)toggleValue:(id)sender
{
toggle = !toggle;
NSLog( @"toggle is now %@", (toggle) ? @"YES" : @"NO" );
[tv reloadData];
}
By referencing the boolean value in tableView:cellForRowAtIndexPath:
and using the code you provided, you can see that the row(s) do in fact update as expected when [table reloadData]
is called.
You can download the sample project here (35KB): http://rdas.me/SampleProject.zip
I hope that this help you. If nothing else it should help you isolate where the problem may in fact reside.
Good luck!
Upvotes: 2
Reputation: 129
I can't find anything wrong in your code. However, please make sure you set your table view data source and delegate like (should be set somewhere in viewDidLoad/viewDidAppear/viewWillAppear):
[tableView setDelegate:self];
[tableView setDataSource:self];
After this, make sure you return the number of rows you need to display from the delegate method:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [yourDataSource count];
}
best of luck!
Upvotes: 0
Reputation: 25632
According to your comment, the tableView
variable you called reloadData
on was nil
.
Common reasons for this are missing links to the IBOutlet in case of using a nib, weak ivars with ARC, or masking the ivar with a local variable with the same name.
Upvotes: 0
Reputation: 324
It's a blind shot without any code, but, if you using dequeueReusableCellWithIdentifier
, it might cause the problem. If you have one cell, you can create it every time in your cellForRowAtIndexPath
instead of re-using already created. Won't effect performance with such tiny table
Upvotes: 3
Reputation: 3870
I usually use this code:
[_myTable beginUpdates];
[... update my cell, adding / removing / changing them ...];
[_myTable endUpdates];
It works on my projects since version 5.0.
Upvotes: 0