2016-12-24 44 views
3

後,我想更新使用線程的進度條,爲explayned here。 我試圖實現這一結果:ObjeciveÇ - 刪除/隱藏NSProgressIndicator循環

  1. 進度條變爲可見
  2. 進度條使用循環更新
  3. 進度條消失

這是我的代碼:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ 

     progressBar.hidden = NO; 

     for (NSInteger i = 1; i <= progressBar.maxValue; i += 20){ 


       [NSThread sleepForTimeInterval:1.0]; 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        [progressBar setDoubleValue:(double)i]; 
        [progressBar displayIfNeeded]; 
       }); 
      } 

     progressBar.hidden = YES; 

    }); 

進度條是在我的ViewController.h int中這樣定義的:

NSProgressIndicator *progressBar

的問題是,酒吧是不是在循環結束去掉,我不知道是否progressBar.hidden = YES;以這種方式工作。

有人可以幫助我嗎?代碼片段會非常有用,特別是如果後面跟着解釋。

+1

主要問題是'progressBar.hidden'尚未像其他進度條更新一樣被分派到主隊列中。 – Rob

回答

5

你正在做什麼不好的原因有兩個。

首先,睡覺線程沒有做,除非你擁有該線程或知道到底是什麼責任有正確的事情。隊列的線程由GCD擁有,您應該將您的工作保持在隊列級別,而不是較低級別。 (來自主隊列的塊總是會在主線程上運行,在某些情況下雖然受限,但全局隊列中的塊可能不會在後臺線程上運行)*

二,原因您問到的問題:在後臺線程中,hidden的設置是非主線程上的UI操作。這是不允許的,因爲它可能會導致UI狀態中的同步問題。除了主線程外,修改Cocoa中的視圖的外觀是不安全的。

你得到了這個問題一半是正確的,調度到主要隊列的setDoubleValue:調用,但設置hidden需要在主線程上。

for循環是不更新屏幕的良好機制。我建議重做你的過程來反覆調用一個方法。 NSTimer是專爲做你正在做的事而設計的。你應該沒有問題找到使用一個例子。

如果您想使用GCD,我建議切換到使用單一dispatch_after()通話,在主隊列中的延遲之後重複運行塊。類似這樣的:

- (void)kickItOff 
{ 
    self.progressBar.hidden = NO; 
    [self updateProgress:0]; 
} 

- (void)updateProgress:(double)progressValue 
{ 
    if(self.progressBar.maxValue <= progressValue){ 
     self.progressBar.hidden = YES; 
     return; 
    } 

    dispatch_time_t oneSecond = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)); 
    dispatch_after(oneSecond, dispatch_get_main_queue(), ^{ 

     [self.progressBar setDoubleValue:progressValue]; 
     [self updateProgress:progressValue + 20]; 
    }); 
} 

您通過調用kickItOff開始更新週期。然後updateProgress:安排循環。這可以讓主線程和運行循環繼續暢通無阻,同時確保您的代碼以您想要的間隔運行。


*更深入的這一點:爲了讓UI真正被吸引到屏幕上,主運行循環需要循環。如果主線程處於睡眠狀態,則不會發生這種情況:對於繪製和接受輸入(並且主要分派隊列也未被處理),整個UI都被鎖定。

+0

喬希的回答比我的更好,更完整。我剛剛回答了問題。他詳細介紹了一個更好的做事方式。 (投票) –

+0

嗯,你是對的,@Rob,除了'dispatch_sync()'情況,我對這一點沒有信心。我會調整措辭;謝謝! –

+0

謝謝您的解釋;) –

2

你的代碼是錯誤的。你正在從後臺線程進行UI調用,這是不允許的。您需要調用來包裝改變進度條的狀態的呼叫(包括隱藏設置爲True或False)以dispatch_async(dispatch_get_main_queue()){}

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ 
      dispatch_async(dispatch_get_main_queue())^{ 
       progressBar.hidden = NO; 
      } 

      for (NSInteger i = 1; i <= progressBar.maxValue; i += 20){ 


        [NSThread sleepForTimeInterval:1.0]; 
        dispatch_async(dispatch_get_main_queue(), ^{ 
         [progressBar setDoubleValue:(double)i]; 
         [progressBar displayIfNeeded]; 
        }); 
       } 

      dispatch_async(dispatch_get_main_queue())^{ 
       progressBar.hidden = YES; 
      } 

     }); 

我推測這只是一個學習鍛鍊?

+0

感謝您的努力:+1 –