Wilhelm Michaelsen
Wilhelm Michaelsen

Reputation: 663

Update label on UITableViewCell

I have a NSTimer that calls this method every fourth second:

- (void)timerDecrement
{
    timerCount = timerCount-1;  
    [OtherViewControllerAccess updateTimeLeftLabel];  
}

In the updateTimeLeftLabel in the other class:

- (void)updateTimeLeftLabel
{
    int timeLeft = OtherClassAccess.timerCount;

    UILabel *timeLeftLabel = [[UILabel alloc] initWithFrame:CGRectMake(200, 10, 120, 20)];
    timeLeftLabel.text = [NSString stringWithFormat:@"Tid kvar: %ih", timeLeft];
    [cell addSubview:timeLeftLabel];
}

Basically I want my app to update a label in a cell in the tableview with the current time left, but the above method doesn't do anything to the call. So my question is, how can I add this subview to the cell outside the cellForRowAtIndexPath:delegate method, and then make it update that label every time the method is called.

Upvotes: 1

Views: 2510

Answers (5)

Nikunj Acharya
Nikunj Acharya

Reputation: 797

You can reload whole table or some specific rows but that needs connection of datasource with your views . You have to change your dataset first and then you have to call

[self.tableview reloadData]; 

another method is that, after changing dataset call

[self.tableview reloadRowsAtIndexPaths:indexPath withAnimation:animation];

2nd method requires indexPath i.e. you know that which cell you need to edit . My problem was same . In my project there were 2 TextFields and 1 label in each cell . Now depending on the values of 2 textfields, I have to show their multiplication in UILabel. and this is my code.

-(void)textFieldDidChange:(id)sender{
    UITextField *_sender = (UITextField *)sender;
    int tag = _sender.tag;
    int row = tag / 3;

    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
    ((UILabel *)[[self.tableView cellForRowAtIndexPath:indexPath] viewWithTag:row * 3 + 2]).text = @"hello";
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    NSLog(@"here");
    static NSString *CellIdentifier = @"procedureDetailsCell";
    UITableViewCell *cell = (procedureCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if ( cell == nil ) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    [((procedureCell *)cell).Quantity setTag:indexPath.row + 0];
    [((procedureCell *)cell).Quantity addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];

    [((procedureCell *)cell).Cost setTag:indexPath.row + 1];
    [((procedureCell *)cell).Cost addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];

    [((procedureCell *)cell).total setTag:indexPath.row + 2];

    return cell;
}

Logic is simple I have used Custom TableViewCell which contains 2 textfields and 1 label. when one of the two textfield's value is changed we are calling "textFieldDidChange" method which finds indexpath and then find UITableViewcell and then updates its lastview's text value, that is our UILabel. we have to give unique tag to each of our views .

Upvotes: 0

Akshat Singhal
Akshat Singhal

Reputation: 1801

Why don't you put that value (which you want to display in the cell) in a variable and assign a UILabel that value. In your updateTimeLeftLabel just call [self.tableView reloadData].

Upvotes: 0

Rufel
Rufel

Reputation: 2660

Here is how I did something similar. I created a custom UITableViewCell class that has a timestamp UILabel:

@property (nonatomic) UILabel *labelTimestamp;

In that cell's layoutSubviews, I update the label size based on its title.

- (void)layoutSubviews {
    [super layoutSubviews];
    [self.labelTimestamp sizeToFit];
    ...
}

I then have an NSTimer firing every minute in my UIViewController that update that label in every visible cell (you could adapt to update only one cell with a specific indexPath).

- (void)timerDidFire
{
    NSArray *visibleCells = [self.tableView visibleCells];
    for (GroupViewCell *cell in visibleCells) {
        NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
        [cell.labelTimestamp setText:[self.groupController statusUpdateDateAtIndexPath:indexPath]];
        [cell setNeedsLayout];
    }
}

Upvotes: 3

Duncan C
Duncan C

Reputation: 131408

So my question is, how can I add this subview to the cell outside the cellForRowAtIndexPath:delegate method, and then make it update that label every time the method is called.

The answer is, don't add subviews to a table view cell outside of cellForRowAtIndexPath. The cells belong to the table view, and you absolutely, categorically, should NOT try to modify them. That's the table view's job.

Just as a small example of what's wrong with your code, you would be adding an ever-increasing number of label views to your table view cell, one every 1/4 second. That's bad.

Second point: Which cell is "cell"? A table view manages a whole table of cells. If the user scrolls, some cells are scrolled off-screen and replaced with different cells.

Instead, you should figure out which indexPath contains the cell with your data in it, change the data in your model, and tell your table view to update the cell at the appropriate indexPath. That will cause it to redraw with updated contents.

Upvotes: 3

atxe
atxe

Reputation: 5079

I would keep the set up of the cell's centralized in cellForRowAtIndexPath: method. You can keep using your NSTimer to call reloadRowsAtIndexPaths:withRowAnimation: with the indexes of the cell/cells you want to update and therefore cellForRowAtIndexPath: will be called again.

Upvotes: 2

Related Questions