2012-03-02 177 views
0

我已经阅读了所有我能找到的相关问题,但仍然卡住了,所以我希望有人能够发现我的推理错误。即使更新从主线程调用,UI也不会更新

我想定期更新一些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()产生相同的结果。

+0

什么是“someTimeDependentValue”?一个浮点数我想.. – 2012-03-02 15:26:31

+1

你试过用NSTimer吗?也许在viewDidLoad中,你启动了一个NSTimer。打勾时,让它执行你的UI更新。在单个视图中使用2个独立的自引用过程有点令人困惑。 – Jeremy 2012-03-02 15:27:12

+0

@RaphaelAyres是的。 – Tom 2012-03-02 15:40:11

回答

1

很可能你的格式声明错误。

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

确保someTimeDependentValue是一个浮点数。如果它是一个整数,它可能会被格式化为0.0000。

Here's a repo显示您描述的工作版本。无论什么错误都与线程无关。

+0

换句话说,你是说我的代码正如我在我的问题中列出的那样应该工作? – Tom 2012-03-02 16:13:18

+0

它正在回购。我几乎只是将你的代码复制并粘贴到UIViewController的一个子类中。我碰到的唯一障碍是我最初将tdv(我创建的一个实例变量替换someTimeDependentValue)声明为int,因为我没有注意到你的stringWithFormat是要求float/double。 – 2012-03-02 16:16:15

+0

这很奇怪。我在该方法中也有一个'NSLog()',这就是打印(更新)值。所以我非常确定的一件事是格式声明是正确的,我提供的价值也是正确的。我会更新我的问题以反映这一点。 – Tom 2012-03-02 16:20:17

0

为了扩大对我的评论,下面是可能使用的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 = ...; 
} 

还有一个更复杂的方法,我在我的项目中被广泛使用。这就是引擎的概念。

我会有一个引擎,使用计时器在后台运行。在关键时刻,它会使用dispatch_async/dispatch_get_main_thread()在主线程上发布通知NSNotificationCenter,然后您的任何一个视图都可以通过更新其UI来订阅和处理该通知。