如何在长时间运行的循环中更新Cocoa中的进度条?

Nic*_*ick 5 macos cocoa objective-c

我有一个while循环,运行了很多秒,这就是为什么我想在该过程中更新进度条(NSProgressIndicator),但它只在循环完成后更新一次.顺便说一下,如果我想要更新标签文本,也会发生同样的情况.

我相信,我的循环会阻止该应用程序的其他事情发生.必须有另一种技术.这与线程有什么关系吗?我是在正确的轨道上吗?有人可以给我一个简单的例子,如何"优化"我的应用程序?

我的应用程序是一个Cocoa应用程序(Xcode 3.2.1),我的这两种方法Example_AppDelegate.m:

// This method runs when a start button is clicked.
- (IBAction)startIt:(id)sender {
    [progressbar setDoubleValue:0.0];
    [progressbar startAnimation:sender];
    running = YES; // this is a instance variable

    int i = 0;
    while (running) {
        if (i++ >= processAmount) { // processAmount is something like 1000000
            running = NO;
            continue;
        }

        // Update progress bar
        double progr = (double)i / (double)processAmount;
        NSLog(@"progr: %f", progr); // Logs values between 0.0 and 1.0
        [progressbar setDoubleValue:progr];
        [progressbar needsDisplay]; // Do I need this?

        // Do some more hard work here...
    }
}

// This method runs when a stop button is clicked, but as long
// as -startIt is busy, a click on the stop button does nothing.
- (IBAction)stopIt:(id)sender {
    NSLog(@"Stop it!");
    running = NO;
    [progressbar stopAnimation:sender];
}

我是Objective-C,Cocoa和带UI的应用程序的新手.非常感谢您提供任何有用的答案.

Enc*_*ada 15

如果您正在为Snow Leopard构建,我认为最简单的解决方案是使用块和Grand Central Dispatch.

以下代码显示了startIt:使用GCD时方法的外观.

stopIt:编写它时,您的方法应该可以正常工作.它之前没有工作的原因是鼠标事件发生在主线程上,因此按钮没有响应你,因为你正在主线程上工作.现在应该已经解决了这个问题,因为现在使用GCD将工作放在不同的线程上.尝试代码,如果它不起作用,请告诉我,我会看到我是否在其中犯了一些错误.

// This method runs when a start button is clicked.
- (IBAction)startIt:(id)sender {

    //Create the block that we wish to run on a different thread.
    void (^progressBlock)(void);
    progressBlock = ^{

    [progressbar setDoubleValue:0.0];
    [progressbar startAnimation:sender];
    running = YES; // this is a instance variable

    int i = 0;
    while (running) {
        if (i++ >= processAmount) { // processAmount is something like 1000000
            running = NO;
            continue;
        }

        // Update progress bar
        double progr = (double)i / (double)processAmount;
        NSLog(@"progr: %f", progr); // Logs values between 0.0 and 1.0

        //NOTE: It is important to let all UI updates occur on the main thread,
        //so we put the following UI updates on the main queue.
        dispatch_async(dispatch_get_main_queue(), ^{
            [progressbar setDoubleValue:progr];
            [progressbar setNeedsDisplay:YES];
        });

        // Do some more hard work here...
    }

    }; //end of progressBlock

    //Finally, run the block on a different thread.
    dispatch_queue_t queue = dispatch_get_global_queue(0,0);
    dispatch_async(queue,progressBlock);
}
Run Code Online (Sandbox Code Playgroud)