У меня есть 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. Большое спасибо за любой полезный ответ.
Если вы строите для 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);
}
Я полагаю, мой цикл предотвращает другие вещи этого приложения.
Верно. Тебе нужно как-то разбить это.
Один из способов - это таймер, когда вы постепенно сокращаете очередь в обратном вызове таймера. Другой вариант - обернуть код для обработки одного элемента в подклассе NSOperation и создать экземпляры этого класса (операций) и поместить их в NSOperationQueue.
Это связано с потоками или чем-то в этом роде?
Не обязательно. NSOperations выполняются в потоках, но NSOperationQueue обрабатывает создание потока за вас. Таймер - это однопоточное решение: каждый таймер запускается в потоке, который вы его запланировали. Это может быть преимуществом или недостатком - решать вам.
См. раздел тем моего введения в Cocoa для получения более подробной информации.
Вы можете попробовать этот код ..
[progressbar setUsesThreadedAnimation:YES];