我正在做一个非常简单的iOS / ObjC程序。单击一个按钮,它通过for..next循环并显示计数器和图片。
for (int i=0; i <= numberOfExercises; i++) {
exerciseName = [exercises objectAtIndex:j][0];
[self.lastLabel setText:exerciseName];
[self.lastLabel setNeedsDisplay];
usleep(1000000);
NSLog(@"Count: %d Name:%@", i, exerciseName);
}
但是,它没有更新屏幕上的实际文本字段。
我已经尝试过我所知道的一切,而且我只能看到它。
(IBAction)btnExerciseClicked:(id)sender {
for (int i=0; i <= numberOfExercises; i++) {
exerciseName = [exercises objectAtIndex:j][0];
exerciseImageName = [exercises objectAtIndex:j][1];
exerciseImageName = [exerciseImageName stringByAppendingString:@".jpg"];
self.exerciseImage.image = [UIImage imageNamed:exerciseImageName];
[self.ExerciseName setText:exerciseName];
[self.ExerciseName setNeedsDisplay];
[self.exerciseImage setNeedsDisplay];
}
我已将该块放在那里:
double delayInSeconds = 0.1;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
NSLog(@"inside the block");
[self.ExerciseName setText:exerciseName];
[self.ExerciseName setNeedsDisplay];
[self.exerciseImage setNeedsDisplay];
});
我在循环开始之前完成了直接分配:
exerciseName = [exercises objectAtIndex:5][0];
[self.ExerciseName setText:exerciseName];
[self.ExerciseName setNeedsDisplay];
NSLog(@"Name: %@", self.ExerciseName.text);
我甚至为它编写了一个单独的方法:
-(void) myCycleDisplay: (NSString *) imageName
nameOfExercise: (NSString *) exerciseName
voiceOver: (BOOL) useVoiceOver
countDown: (BOOL) useCountDown
beep: (BOOL) useBeep{
[self.ExerciseName setText:exerciseName];
[self.ExerciseName setNeedsDisplay];
self.exerciseImage.image = [UIImage imageNamed:imageName];
}
毕竟,在方法完成之后,STILL才会显示。延迟:usleep(1000000);
我确认数据在元素中。我在代码和IB中设置了元素。
该应用程序非常简单,屏幕上按下按钮,加载数据,行走数组并根据数组中的元素更新显示项目。
数据在文本字段中,已经确认。它甚至会显示它们,但只有在退出方法后才会显示它们。
退出方法后,文本/图片会正确显示。
所以,作为一个测试,我让for..next循环运行两次并反复点击按钮。确实在离开方法后它显示正确。
我无法在方法中更新显示屏。 (这也包括滑块)。
为什么我必须退出方法才能让显示更新?
答案 0 :(得分:1)
我认为解决问题的最简单方法是将整个for循环转储到另一个队列中。
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
for (int i=0; i <= numberOfExercises; i++) {
NSString *exerciseName = [exercises objectAtIndex:i][0];
dispatch_async(dispatch_get_main_queue(), ^{
[self.lastLabel setText:exerciseName];
[self.lastLabel setNeedsDisplay];
});
usleep(1000000);
NSLog(@"Count: %d Name:%@", i, exerciseName);
}
});
还有三项更改。
将[exercises objectAtIndex:j]
更改为[exercises objectAtIndex:i]
我认为这是你的错误
将exerciseName
定位到块的本地。
我本来可以声明exerciseName
__block
,但是让整个事情变得更加容易。
在dispatch_async(dispatch_get_main_queue(), ^{ … });
必须在主队列上进行UI更新。
请注意,这是一个错误的解决方案。你应该完全重新思考你的方法。我会将此逻辑移入其自己的单独类中,然后使用通知来更新UI。
答案 1 :(得分:0)
当您致电usleep(1000000)
时,您阻止主要排队。 UI更新发生在主队列上,但您阻止该队列,因此它们不会发生。此外,UI更新通常不会发生,直到您完成当前通过事件循环 - 从用户点击按钮,通过您的方法做任何需要做的事情,继续直到您的方法完成< / strong>即可。然后UIKit更新UI。你需要让你的方法完成,因为这是UIKit的工作方式。
我不确定你要做什么。如果您想定期更新您的用户界面,请查看NSTimer
。
答案 2 :(得分:0)
我希望我能够很好地理解这个问题,给出一个相关的答案,如果我没有,我会道歉。以下是我的看法:
当前实现的确如此:显示已更新,系统会在再次更新显示之前休眠一段时间。
该方法的问题在于,在iOS设备上进行交互式操作时常用的UIKit框架可以称为&#34; indirect&#34; 。例如,当更新标签的 .text 属性时,不会绘制文本,而是通知系统应更新显示。 UIKit会定期检查是否请求更新,如果是,则重绘显示。
所有这一切都在&#34;主队列&#34;通过顺序执行添加到其中的代码块(作为旁注,这与Javascript在浏览器中的工作方式不同)。这意味着只要执行了一些代码块,主队列的其他所有内容都不会出现,应用程序将停止交互并更新显示。因此,使用UIKit的方法是快速通知它必要的更改并完成功能。因此,在主队列上永远不会进行长时间的计算或&#34;睡眠&#34; 。
在这个问题的上下文中,这留下了定时更新的问题:我们希望在一段时间过期后更新UI。有两种解决方案可以想到:
(我已切换到Swift和最新的API,因此在Objective-C中方法名称可能不完全正确。)
如果我误解了这个问题或者您是否需要示例代码或进一步澄清,请告诉我。
祝你好运!