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

4

我想在我的应用程序中将进度条显示为确定的,而不是不确定的。但是,将其设置为确定时无效(对于不确定的情况,它可以正常工作)。我已经阅读了一些有关此问题的其他答案,但它们都没能解决问题。任何帮助将不胜感激-谢谢!

@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个回答

4
您的doSomething方法阻塞了主线程,导致运行循环不会循环,进而导致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),则它将是我的首选。


太棒了的例子。我更新了我的问题,以反映出带有你的代码示例的工作版本;如果我漏掉了什么或者你发现任何问题,请告诉我。再次感谢你;-) - Joe Habadas
你需要发布你的新代码,我才能提出任何建议。你又阻塞了主线程吗?我建议你发布一个新问题,并附上你的新代码。 - Andrew Madsen
不,这段代码并不新 —— 它只是消除了 (IBAction) 的存在,而改成了 void(也就是你展示的方法)。我把它改成了 void,现在进度条不再显示(或者更新进度)。可能有什么特殊的地方我忽略了吗?谢谢。您每 5 秒才能编辑一次评论。(点击此框以关闭) - Joe Habadas
IBAction 只是 void 的一个 #define(见 AppKit/NSNibDeclarations.h),所以如果您真的只做了这个改变,那么您编译后的可执行文件将是 完全相同 的。现在,您是如何调用该方法的,如果不是通过按钮?改变方法的调用方式很可能是新行为的原因。仅仅将 IBAction 改为 void 并没有任何意义。 - Andrew Madsen
我没有看到你的代码就无法提供任何想法。我真的鼓励你发布一个新问题,并在这里留下链接,以便我能够找到它。 - Andrew Madsen
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接