Question

I've read all related questions I could find but I'm still stuck, so I hope someone will spot my reasoning error.

I'm trying to periodically update some UIView. For simplicity, I've reduced the code to what's below. Summary: In viewDidLoad, I call a method on a new background thread. That method calls a method on the main thread which is supposed to update some UILabel. The code seems to work correctly: the background thread is not the main thread and the method calling the UILabel update is on the main thread. In code:

In viewDidLoad:

[self performSelectorInBackground:@selector(updateMeters) withObject:self];

This creates a new background thread. My method updateMeters (for simplicity) now looks like this:

if ([NSThread isMainThread]) { //this evaluates to FALSE, as it's supposed to
    NSLog(@"Running on main, that's wrong!");
}
while (i < 10) {
    [self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:NO];
//The code below yields the same result
//        dispatch_async(dispatch_get_main_queue(), ^{
//            [self updateUI];
//        });
    [NSThread sleepForTimeInterval: 1.05];
    ++i;
}

Finally, updateUI does just that:

if ([NSThread isMainThread]) { //Evaluates to TRUE; it's indeed on the main thread!
    NSLog(@"main thread!");
} else {
    NSLog(@"not main thread!");
}
NSLog(@"%f", someTimeDependentValue); //logs the value I want to update to the screen
label.text = [NSString stringWithFormat:@"%f", someTimeDependentValue]; //does not update

For all I know, this should work. But it doesn't, unfortunately... The commented out dispatch_async() yields the same result.

Was it helpful?

Solution

Most likely you have your format statement wrong.

label.text = [NSString stringWithFormat:@"%f", someTimeDependentValue];

Make sure that someTimeDependentValue is a float. If it is an int it will likely get formatted to 0.0000.

Here's a repo showing a working version of what you describe. Whatever is wrong is not related to the threading.

OTHER TIPS

To expand on my comment, here's a scenario that might be best achieved using a NSTimer:

-(void)viewDidLoad
{
       NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:<number of seconds per tick> target:self selector:@selector(timerTick:) userInfo:nil repeats:YES];
}

-(void)timerTick:(id)sender
{
      label.text = ...;
}

There is a more elaborate approach which I use extensively in my projects. And that is the concept of an engine.

I would have an engine that runs in the background using a timer. And at key moments, it would post a notification using NSNotificationCenter on the main thread using dispatch_async/dispatch_get_main_thread() and any one of your views can then subscribe and handle that notification by updating their UI.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top