2010-03-24 13 views
5

我有一個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,可可和應用程序的UI。非常感謝您提供有用的答案。

回答

15

如果您正在爲雪豹,最簡單的解決辦法是在我使用的塊和中央調度的意見。

以下代碼顯示如何在使用GCD時使用startIt:方法。

您的stopIt:方法應該可以正常工作。之前不工作的原因是鼠標事件發生在主線程上,因此按鈕沒有響應你,因爲你正在主線程上工作。這個問題現在應該已經解決了,因爲現在這項工作已經與GCD分道揚a了。嘗試一下代碼,如果它不起作用,請告訴我,我會看看我是否犯了一些錯誤。

// 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); 
} 
+0

非常感謝,我給這是一個嘗試這個週末! – Nick 2010-03-26 10:10:59

+0

這就是我一直在尋找的。工作正常,這給了我一個很好的起點來了解更多。謝謝! – Nick 2010-03-30 22:56:58

+0

感謝您的Enchilada!我剛剛學到了一些我不知道的東西!非常興奮地發現關於塊和GCD! – 2011-08-24 02:14:22

2

我相信,我的循環阻止該應用程序的其他事情發生。

正確。你需要以某種方式打破這一點。

一種方法是一個計時器,與你在定時器回調中一次一點點地減少隊列。另一種方法是包裝代碼以處理NSOperation子類中的一個項目,並創建該類(操作)的實例並將它們放入NSOperationQueue中。

這是否與線程有關?

不一定。 NSOperations在線程上運行,但NSOperationQueue將爲您處理產生線程。計時器是一個單線程解決方案:每個計時器都運行在您安排的線程上。這可能是一個優勢或劣勢 - 你決定。

請參閱the threads section of my intro to Cocoa瞭解更多詳情。

3

你可以試試這個代碼..

[progressbar setUsesThreadedAnimation:YES]; 
2

這個工作對我來說,這是從別人的答案對自己的一個組合似乎沒有(至少對我來說)工作:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ 
    //do something 
    dispatch_async(dispatch_get_main_queue(), ^{ 
    progressBar.progress = (double)x/(double)[stockList count];    
    }); 
    //do something else 
}); 
相關問題