Пользовательский интерфейс не обновляется, хотя обновления вызываются из основного потока - PullRequest
0 голосов
/ 02 марта 2012

Я прочитал все связанные вопросы, которые смог найти, но все еще застрял, поэтому я надеюсь, что кто-то заметит мою ошибку в рассуждениях.

Я пытаюсь периодически обновлять некоторые UIView. Для простоты я сократил код до следующего. Резюме: в viewDidLoad я вызываю метод в новом фоновом потоке. Этот метод вызывает метод в главном потоке, который должен обновить некоторую UILabel. Кажется, код работает правильно: фоновый поток не является основным потоком, а метод, вызывающий обновление UILabel, находится в основном потоке. В коде:

В viewDidLoad:

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

Это создает новый фоновый поток. Мой метод updateMeters (для простоты) теперь выглядит так:

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;
}

Наконец, updateUI делает именно это:

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

Насколько я знаю, это должно работать. Но, к сожалению, это не так ... Закомментированный dispatch_async() дает тот же результат.

Ответы [ 2 ]

1 голос
/ 02 марта 2012

Скорее всего, вы неправильно указали формат.

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

Убедитесь, что someTimeDependentValue является плавающей точкой. Если это int, он, вероятно, будет отформатирован до 0,0000.

Вот репозиторий , показывающий рабочую версию того, что вы описываете. Все, что не так, не относится к потокам.

0 голосов
/ 02 марта 2012

Чтобы расширить мой комментарий, вот сценарий, который может быть наилучшим образом реализован с помощью 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 = ...;
}

Существует более сложный подход, который я широко использую в своих проектах.И это концепция двигателя.

Я хотел бы иметь двигатель, который работает в фоновом режиме, используя таймер.А в ключевые моменты он будет публиковать уведомление, используя NSNotificationCenter, в главном потоке, используя dispatch_async / dispatch_get_main_thread(), и любое из ваших представлений может затем подписаться и обработать это уведомление, обновив свой пользовательский интерфейс.

...