2016-12-20 11 views
0

というメソッドでは更新されません。かなり簡単なiOS/ObjCプログラムを実行しています。ボタンをクリックすると、for..nextをループし、カウンタと写真が表示されます。iOSのUI要素は、

for (int i=0; i <= numberOfExercises; i++) { 
    exerciseName = [exercises objectAtIndex:j][0]; 
    [self.lastLabel setText:exerciseName]; 
    [self.lastLabel setNeedsDisplay]; 
    usleep(1000000); 
    NSLog(@"Count: %d Name:%@", i, exerciseName); 
} 

ただし、画面上の実際のテキストフィールドは更新されません。

私が知っているすべてを試しましたが、見えないものがあります。

double delayInSeconds = 0.1; 
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds *  NSEC_PER_SEC)); 
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
    NSLog(@"inside the block"); 
    [self.ExerciseName setText:exerciseName]; 
    [self.ExerciseName setNeedsDisplay]; 
    [self.exerciseImage setNeedsDisplay]; 
}); 

、ループが始まる前に私が直接割り当てを行ってきた:

(IBAction)btnExerciseClicked:(id)sender { 
    for (int i=0; i <= numberOfExercises; i++) { 
     exerciseName = [exercises objectAtIndex:j][0]; 
     exerciseImageName = [exercises objectAtIndex:j][1]; 
     exerciseImageName = [exerciseImageName stringByAppendingString:@".jpg"]; 
     self.exerciseImage.image = [UIImage imageNamed:exerciseImageName]; 
     [self.ExerciseName setText:exerciseName]; 
     [self.ExerciseName setNeedsDisplay]; 
     [self.exerciseImage setNeedsDisplay]; 
    } 

は、私はそこにブロックを置いてきました

exerciseName = [exercises objectAtIndex:5][0]; 
[self.ExerciseName setText:exerciseName]; 
[self.ExerciseName setNeedsDisplay]; 
NSLog(@"Name: %@", self.ExerciseName.text); 

私は」別の方法を書いても:

そして結局のところ、メソッドが完了するまで表示されません。遅延を入れて:usleep(1000000);

データが要素内にあることを確認しました。私はコードとIBで要素を設定しました。

アプリはかなりシンプルで、画面上でボタンが押され、データが読み込まれ、配列が歩かれ、表示アイテムが配列内の要素に基づいて更新されます。

データはテキストフィールドにありますが、これは確認済みです。それはメソッドを終了した後にのみ表示されます。

メソッドが終了すると、text/picが正しく表示されます。

したがって、テストとして、for..nextループを2回実行し、ボタンを何度も繰り返しクリックしました。確かに、メソッドを離れると適切に表示されます。

このメソッドでは、表示を更新することができません。 (これにはスライダも含まれます)。

ディスプレイを更新するためにメソッドを終了する必要があるのはなぜですか?

+0

新しいビューコントローラーを追加して、すべてのUI要素を移動しましたが、まだ更新されません。 – KarlJay

+0

各ループの 'ExerciseName'と' exerciseImage'の値を上書きする深い意味はありますか?実際には 'setNeedsDisplay'行は必要ありません。すべてのUI更新がメインスレッド上で実行されるように注意してください。 – vadian

+0

実際にここで何をしたいですか?配列から最後のオブジェクトデータをテキストフィールドや画像などに入力したい場合、ここで試してみる必要がありますか? – CodeChanger

答えて

1

あなたの問題を解決する最も簡単な方法は、forループ全体を別のキューにダンプすることです。

dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ 
    for (int i=0; i <= numberOfExercises; i++) { 
     NSString *exerciseName = [exercises objectAtIndex:i][0]; 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      [self.lastLabel setText:exerciseName]; 
      [self.lastLabel setNeedsDisplay]; 
     }); 
     usleep(1000000); 
     NSLog(@"Count: %d Name:%@", i, exerciseName); 
    } 
}); 

さらに3つの変更があります。

  1. は、私は、これは

  2. がブロックにローカルexerciseNameを作ったあなたの部分の間違いだったと思う[exercises objectAtIndex:j]

    [exercises objectAtIndex:i]に変更します。

    私はexerciseName__blockの宣言を作成できましたが、すべてをローカルにするほうが簡単です。dispatch_async(dispatch_get_main_queue(), ^{ … });

    UIのアップデートにラベルを設定ラップ

  3. がメインキューになされなければなりません。


注、これは悪いソリューションです。あなたはあなたのアプローチを完全に再考すべきです。このロジックを別のクラスに移してから、通知を使用してUIを更新します。

+0

これはUITextでは機能しましたが、スライダーや画像ビューでは機能しませんでした。私はこれらを別のVCに入れますが、呼び出し元のVCからUIの更新を呼び出す必要があります。 – KarlJay

+0

失敗したコードを投稿してください。だから皆がそれを見ることができます。 –

0

usleep(1000000)に電話すると、がメインキューをブロックしています。 UI更新はメインキューで行われますが、そのキューはブロックされているため、発生しません。また、一般的なUIの更新は、ボタンをタップしたユーザーから、必要な操作をしてから、のメソッドが終了するまで、イベントループの現在のパスを終了するまで発生しません。 UIKitはUIを更新します。 UIKitがどのように機能するので、メソッドを終了させる必要があります。

私はあなたが何をしようとしているのか正確にはわかりません。間隔を置いてUIを更新する場合は、NSTimerを参照してください。

0

私は問題を十分に理解して適切な回答を得たことを願っています。ここに私はそれを見る方法です:

  • 練習のセットが次々に行われます。
  • 練習には一定の時間がかかります。
  • 運動が始まると、運動の名前と関連する画像が表示されます。

現在の実装は正確に:ディスプレイが更新され、ディスプレイを再び更新する前にシステムが一定時間スリープします。

このアプローチの問題点は、iOSデバイスでインタラクティブな作業を行うときによく使用されるUIKitフレームワークが、「indirect」と呼ばれるものであることです。たとえば、.textラベルのプロパティが更新された場合、テキストは描画されず、代わりに、ディスプレイを更新する必要があることが通知されます。 UIKitは更新が要求されているかどうかを定期的にチェックし、更新されている場合は表示が再描画されます。

これはすべて、「メインキュー」上に追加されたコードブロックを順番に実行することによって行われます(副次的なことは、Javascriptがブラウザで動作する方法とは異なります)。これは、コードの一部が実行されている限り、メインキューの他のものは表示されず、アプリケーションはインタラクティブでなくなり、表示を更新することを意味します。したがって、UIKitを使用する方法は、必要な変更をすばやく通知して機能を終了することです。結果的に、長い計算をしたり、メインキューの"sleep"をオンにすることはありません。

この質問の文脈では、これは時間がかかる更新の問題を残します。一定の時間が経過した後にUIを更新する必要があります。

  1. "標準的な"ものにはNSTimerクラスを使用します。
  2. UIの更新が必要な場合は、[UIScreen mainScreen]にCADisplayLinkクラスと便利な[UIScreen displayLinkWithTarget:selector:]メソッドを作成する方法があります。それは何ですか、それはセレクタ(現在は秒あたり約60回ですが、それほど頻繁に呼び出されないように設定することができます)を呼び出します。カウントダウンタイマーやプログレスバーなどのUIエレメントを頻繁に更新するようなものには理想的です。

(メソッド名がObjective-Cでは正確でないように私はSwiftと最新のAPIに切り替えました)

質問が誤解されている場合や、サンプルコードが必要な場合や詳細な説明が必要な場合は、教えてください。

幸運を祈る!

関連する問題