Как я обновляю индикатор выполнения в Какао во время длительного цикла?

У меня есть a while цикл, который работает в течение многих секунд и вот почему я хочу обновить индикатор выполнения (NSProgressIndicator) во время того процесса, но он обновляет только однажды после того, как цикл закончился. То же происходит, если я хочу обновить текст метки, между прочим.

Я верю, мой цикл предотвращает другие вещи того приложения произойти. Должна быть другая техника. Это имеет отношение к потокам или чему-то? Я на правильном пути? Кто-то может дать мне простой пример, как “оптимизировать” мое приложение?

Мое приложение является Приложением Какао (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, Какао и приложениями с UI. Большое спасибо за любой полезный ответ.

5
задан Nick 24 March 2010 в 16:47
поделиться

3 ответа

Если вы строите для 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);
}
15
ответ дан 18 December 2019 в 07:08
поделиться

Я полагаю, мой цикл предотвращает другие вещи этого приложения.

Верно. Тебе нужно как-то разбить это.

Один из способов - это таймер, когда вы постепенно сокращаете очередь в обратном вызове таймера. Другой вариант - обернуть код для обработки одного элемента в подклассе NSOperation и создать экземпляры этого класса (операций) и поместить их в NSOperationQueue.

Это связано с потоками или чем-то в этом роде?

Не обязательно. NSOperations выполняются в потоках, но NSOperationQueue обрабатывает создание потока за вас. Таймер - это однопоточное решение: каждый таймер запускается в потоке, который вы его запланировали. Это может быть преимуществом или недостатком - решать вам.

См. раздел тем моего введения в Cocoa для получения более подробной информации.

2
ответ дан 18 December 2019 в 07:08
поделиться

Вы можете попробовать этот код ..

[progressbar setUsesThreadedAnimation:YES];
3
ответ дан 18 December 2019 в 07:08
поделиться