在名为

时间:2016-12-20 10:33:59

标签: ios objective-c

我正在做一个非常简单的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循环运行两次并反复点击按钮。确实在离开方法后它显示正确。

我无法在方法中更新显示屏。 (这也包括滑块)。

为什么我必须退出方法才能让显示更新?

3 个答案:

答案 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);
    }
});

还有三项更改。

  1. [exercises objectAtIndex:j]更改为[exercises objectAtIndex:i]

    我认为这是你的错误

  2. exerciseName定位到块的本地。

    我本来可以声明exerciseName __block,但是让整个事情变得更加容易。

  3. dispatch_async(dispatch_get_main_queue(), ^{ … });

    中设置标签

    必须在主队列上进行UI更新。

  4. 请注意,这是一个错误的解决方案。你应该完全重新思考你的方法。我会将此逻辑移入其自己的单独类中,然后使用通知来更新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。有两种解决方案可以想到:

  1. &#34;典型&#34;一个人会使用NSTimer类;
  2. 如果需要对UI进行持续更新,则可以使用CADisplayLink类和方便的[UIScreen displayLinkWithTarget:selector:]方法在[UIScreen mainScreen]上创建一个。它的作用是,它及时调用选择器进行屏幕更新(目前,每秒约60次,但您可以将其配置为不经常调用)。它非常适合倒数计时器和频繁更新UI元素,如进度条。
  3. (我已切换到Swift和最新的API,因此在Objective-C中方法名称可能不完全正确。)

    如果我误解了这个问题或者您是否需要示例代码或进一步澄清,请告诉我。

    祝你好运!