Objective-C,如何显示确定的进度条?

Posted

技术标签:

【中文标题】Objective-C,如何显示确定的进度条?【英文标题】:Objective-C, how to display determinate progress bar? 【发布时间】:2012-06-04 23:04:46 【问题描述】:

我想在我的应用程序中将进度条显示为确定的而不是不确定的。但是在将其设置为确定时它不起作用(对于不确定的工作就很好)。我有read some 的other 对此的回答,尽管它们没有奏效。任何帮助将不胜感激 - 谢谢!

@interface AppDelegate : NSObject <NSApplicationDelegate> 

    IBOutlet NSProgressIndicator *showProgress;



- (IBAction)someMethod:(id)sender 

    [showProgress setUsesThreadedAnimation:YES];   // This works
    [showProgress startAnimation:self];            // This works
    [showProgress setDoubleValue:(0.1)];           // This does not work
    [showProgress setIndeterminate:NO];            // This does not work

    [self doSomething];
    [self doSomethingElse];
    [self doSomethingMore];
    ....

    [barProgress setDoubleValue:(1.0)];            // This does not work
    [barProgress stopAnimation:self];              // This works



更新的代码[工作]:

- (IBAction)someMethod:(id)sender 

    [showProgress setUsesThreadedAnimation:YES];
    [showProgress startAnimation:self];
    [showProgress setIndeterminate:NO];

    [showProgress setDoubleValue:(0.1)];
    [showProgress startAnimation:nil];

    dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(backgroundQueue, ^

        for (NSUInteger i = 0; i < 1; i++) 

            dispatch_async(dispatch_get_main_queue(), ^
                [barProgress incrementBy:10.0];
            );
        

    [self doSomething];

            [showProgress incrementBy:...];

        dispatch_async(dispatch_get_main_queue(), ^

            [showProgress stopAnimation:nil];

        );
    );

    [showProgress setDoubleValue:(1.0)];

【问题讨论】:

【参考方案1】:

您的doSomething 方法阻塞了主线程,导致run loop 不循环,进而导致UI 重绘被阻塞。解决方法是在后台队列中的 doSomething 中执行长时间运行的工作,并定期回调主队列以更新进度条。

我不知道你的 doSomething 方法是做什么的,但为了解释起见,我们假设它运行一个包含 100 步的 for 循环。你会像这样实现它:

- (void)doSomething

    [showProgress startAnimation:nil];
    dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(backgroundQueue, ^
        for (NSUInteger i = 0; i < 100; i++) 
            // Do whatever it is you need to do

            dispatch_async(dispatch_get_main_queue(), ^
                [showProgress incrementBy:1.0];
            );
        
        // Done with long running task
        dispatch_async(dispatch_get_main_queue(), ^
            [showProgress stopAnimation:nil];
        );
    );

请记住,您仍然需要将进度指示器设置为确定,初始化其值并设置适当的 minValue 和 maxValue。

如果您必须在主线程上完成doSomething 中的工作,则可以安排在每个运行循环周期中完成该工作的一小部分,或者在您执行时定期手动旋转运行循环工作,但如果你可以使用它,Grand Central Dispatch (GCD) 将是我的首选。

【讨论】:

——很棒的例子。我用您的代码示例更新了我的问题以反映工作版本;让我知道我是否遗漏任何内容或您发现任何问题。再次 ;-) 嗨——我有一个关于这个的快速问题。当进度条与启动动画的按钮相关联时,它工作正常。但是我不再需要按钮,即使使用 [showProgress startAnimation:self]; 等参数,动画也不再启动有什么想法吗? 你必须发布你的新代码让我给出任何建议。你又阻塞了主线程?我建议用你的新代码发布一个新问题。 不,代码一点也不新——它只是消除了 (IBAction) 而不是 void (这是您展示的方法)。我将其切换为 void,现在进度条不再显示(或进度)。有什么特别的东西我可能会错过吗?谢谢。您只能每 5 秒编辑一次评论。(单击此框可关闭) IBAction 只是 void 的 #define(参见 AppKit/NSNibDeclarations.h),所以如果这真的是您所做的唯一更改,那么您编译的可执行文件将完全相同相同.如果不是通过按钮,您现在如何调用该方法?更改方法的调用方式很可能是新行为的原因。更改 IBAction -> void 本身没有任何意义。

以上是关于Objective-C,如何显示确定的进度条?的主要内容,如果未能解决你的问题,请参考以下文章

在所有元素顶部显示全屏不确定进度条[重复]

如何更新异步任务中的进度条

PHP实现的进度条效果详解

动画进度条以显示网页的进度

在进度条上显示文件复制状态

Symfony Ajax 进度条