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

时间:2016-12-24 22:38:20

标签: ios objective-c nsprogressindicator

我想使用线程更新进度条,如解释here。 我正在努力实现这个结果:

  1. 进度条变得可见
  2. 使用循环
  3. 更新进度条
  4. 进度条消失
  5. 这是我的代码:

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

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

    NSProgressIndicator *progressBar

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

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

2 个答案:

答案 0 :(得分: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];
    });
}

您可以致电kickItOff开始更新周期。然后updateProgress:安排循环。这使主线程和运行循环继续无阻碍地运行,同时确保代码以您想要的间隔运行。

*关于这一点的更深入:为了实际将UI绘制到屏幕上,主运行循环需要循环。如果主线程处于休眠状态,则不会发生:整个UI都被锁定以进行绘制和接受输入(主要的调度队列也不会被处理)。

答案 1 :(得分:2)

你的代码错了。您正在从后台线程进行UI调用,这是不允许的。在调用dispatch_async(dispatch_get_main_queue()){}

时,您需要包含更改进度条状态的调用(包括将隐藏设置为True或False)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
            dispatch_async(dispatch_get_main_queue())^{
              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];
                    });
                }

            dispatch_async(dispatch_get_main_queue())^{
              progressBar.hidden = YES;
            }

        });

我认为这只是一次学习练习?