2016-12-24 15 views
3

スレッドを使用して進捗バーを更新する場合は、explayned hereとします。Objecive C - ループ後に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内で定義されています。

NSProgressIndicator *progressBar

問題はバーがループの最後で削除されていないprogressBar.hidden = YES;がこのように動作するかどうか、私にはわからないということです。

誰かが私を助けることができますか?コードスニペットは実際には便利です。説明が続く場合は特に便利です。

+1

主な問題は、progressBar.hiddenが残りのプログレスバー更新のようにメインキューにディスパッチされていないことです。 – Rob

答えて

5

あなたがしていることは、2つの理由でうまくいかない。

まず、スレッドをスリープ状態にすることは、そのスレッドを所有しているか、それが持つ責任を正確に把握していない限り、正しいことではありません。キューのスレッドは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呼び出しを行っていますが、これは許可されていません。あなたは、私は、これは単なる学習運動です集まる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; 
      } 

     }); 

への呼び出しに(TrueまたはFalseに隠された設定を含む)、プログレスバーの状態を変更する呼び出しをラップする必要がありますか?

+0

あなたの努力をありがとう:+1 –

関連する問題