Objective C - 循环后删除/隐藏NSProgressIndicator

Ema*_*jar 3 objective-c nsprogressindicator ios

我想用线程更新进度条,如此处所述.我正在努力实现这个结果:

  1. 进度条变得可见
  2. 使用循环更新进度条
  3. 进度条消失了

这是我的代码:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{

        progressBar.hidden = NO;

        for (NSInteger i = 1; i <= progressBar.maxValue; i += 20){


                [NSThread sleepForTimeInterval:1.0];
                dispatch_async(dispatch_get_main_queue(), ^{
                    [progressBar setDoubleValue:(double)i];
                    [progressBar displayIfNeeded];
                });
            }

        progressBar.hidden = YES;

    });
Run Code Online (Sandbox Code Playgroud)

进度条在我的ViewController.h中以这种方式定义:

NSProgressIndicator *progressBar

问题是在循环结束时没有删除条形,我不知道是否以progressBar.hidden = YES;这种方式工作.

有人能帮我吗?代码片段非常有用,特别是如果后面有解释的话.

Jos*_*ell 5

你做的事情有两个原因并不好.

首先,除非你拥有该线程或确切知道它具有哪些职责,否则睡眠线程不是正确的做法.队列的线程由GCD拥有,您应该将您的工作保持在队列级别而不是较低级别.(来自主队列的块将始终在主线程上运行.在某些情况下,尽管有限,但是全局队列中的块可能无法在后台线程上运行.*)

第二,你问的问题的原因是:在后台线程上,你的设置hidden是非主线程上的UI操作.这是不允许的,因为它可能导致UI状态中的同步问题.除了主线程之外,修改Cocoa中的视图外观是不安全的.

您将该问题解决了一半,调度到setDoubleValue:调用的主队列,但设置也hidden需要在主线程上.

for循环不是更新屏幕的好机制.我建议重新修改你的程序,重复调用一个方法.一个NSTimer是专为做你正在做什么.您应该毫不费力地找到使用它的示例.

如果您想使用GCD,我建议切换为使用单个dispatch_after()呼叫,在主队列延迟后重复运行一个阻止.像这样的东西:

- (void)kickItOff
{
    self.progressBar.hidden = NO;
    [self updateProgress:0];
}

- (void)updateProgress:(double)progressValue
{
    if( self.progressBar.maxValue <= progressValue ){
        self.progressBar.hidden = YES;
        return;
    }

    dispatch_time_t oneSecond = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC));
    dispatch_after(oneSecond, dispatch_get_main_queue(), ^{

        [self.progressBar setDoubleValue:progressValue];
        [self updateProgress:progressValue + 20];
    });
}
Run Code Online (Sandbox Code Playgroud)

您可以通过调用启动更新周期kickItOff.然后updateProgress:安排循环.这使主线程和运行循环继续无阻碍地工作,同时确保代码以您想要的间隔运行.


*在这一点上更深入:为了实际将UI绘制到屏幕上,主运行循环需要循环.如果主线程处于休眠状态,则不会发生这种情况:整个UI都被锁定以用于绘制和接受输入(并且主分派队列也未被处理).