20

Can someone help me figure this out please?

My UITableViewCell textLabel, does not update until I scroll, or touch it.

The ViewController loads, it shows the right amount of cells. But the content is blank. I have to touch it or scroll to make my textLabel appear.

Am I doing something wrong here?

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
    }

    [[cell textLabel] setFont: [UIFont systemFontOfSize: 32.0]];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        NSDictionary * data = [self timeForObject: [self.months objectAtIndex:indexPath.row]];

        dispatch_async(dispatch_get_main_queue(), ^{

            NSString *time      = [data objectForKey:@"Time"];
            NSString *totalTime = [data objectForKey:@"Total Time"];

            NSString * textLabel  = [NSString stringWithFormat:@" %@ %@",
                                        time, totalTime];

            [[cell textLabel] setText:textLabel];



        });
    });

    return cell;
}

Any help is appreciated

Thank you!

Nuno

EDIT:

A call to [cell setNeedsLayout] fixes this issue. Thank you everyone for your help!

nmdias
  • 3,888
  • 5
  • 36
  • 59
  • Is this a UITableViewController or a ViewController? Try calling [yourTableView reloadData]; in viewDidAppear() – Jens Bergvall Aug 27 '12 at 09:54
  • 1
    You are using multithreading in Loading view of `UITableViewCell`, check this link http://blog.slaunchaman.com/2011/08/14/cocoa-touch-circumventing-uitableviewcell-redraw-issues-with-multithreading/ for the solution, also this http://stackoverflow.com/questions/9352638/cell-imageview-in-uitableview-doesnt-appear-until-selected – Sumanth Aug 27 '12 at 10:01
  • Bigger stretch then I was hoping for unfortunately. But it must be done. Thank you for both resources! Specially the blog, exetremly helpful. – nmdias Aug 27 '12 at 13:44

4 Answers4

11

It seems that just setting the text of the cell is not enough for it to be refreshed. Have you tried putting [cell setNeedsDisplay] after setting the text and see what happens? BTW, since you are already using GCD to compute stuff in the background you should try to avoid doing any work at all on the main queue. I would write that piece of code more like:

NSDictionary *data = [self timeForObject: [self.months objectAtIndex:indexPath.row]];
NSString *time      = [data objectForKey:@"Time"];
NSString *totalTime = [data objectForKey:@"Total Time"];
NSString *textLabel = [NSString stringWithFormat:@" %@ %@", time, totalTime];

dispatch_async(dispatch_get_main_queue(), ^{
    [[cell textLabel] setText:textLabel];
    [cell setNeedsDisplay];
});
Grzegorz Adam Hankiewicz
  • 7,349
  • 1
  • 36
  • 78
7

You seem to be updating the cell on another thread (which is not the main thread)

Try this when you reload the tableview:

Objective-C

dispatch_async(dispatch_get_main_queue(), ^{
    [self.tableView reloadData];
});

Swift

dispatch_async(dispatch_get_main_queue()) {
    self.tableView.reloadData()
}
Tristan
  • 3,301
  • 8
  • 22
  • 27
Nisarg Shah
  • 109
  • 1
  • 5
2

I guess that GCD running your block in main thread with default run loop mode. Try another way:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil)
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];

    [[cell textLabel] setFont: [UIFont systemFontOfSize: 32.0]];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        NSDictionary * data = [self timeForObject: [self.months objectAtIndex:indexPath.row]];
        NSString *time      = [data objectForKey:@"Time"];
        NSString *totalTime = [data objectForKey:@"Total Time"];
        NSString *textLabel  = [NSString stringWithFormat:@" %@ %@", time, totalTime];

        [cell performSelectorOnMainThread:@selector(setText:) withObject:textLabel waitUntilDone:NO modes:@[NSRunLoopCommonModes]]; //instead of using literals you could do something like this [NSArray arrayWithObject:NSRunLoopCommonModes];
    });

    return cell;
}
tikhop
  • 2,012
  • 14
  • 32
1

In swift 5

    DispatchQueue.main.async() {
        self.listView.reloadData()
    }
KeithTheBiped
  • 832
  • 10
  • 21