0

バックグラウンドスレッドで数学計算を実行しています。UITextView にリアルタイムで結果を投稿しようとしています。ただし、バックグラウンド スレッドが完了するまで結果は表示されません。なぜだめですか?

バックグラウンドでメソッドを起動し、

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^() {
    [self v2];
});

バックグラウンド スレッド メソッドの形式は、

- (void) v2 {
    NSString *result;
    // ... loop a bunch of times generating lots of results
    for (bunch of stuff to compute) {
      // If using dispatch_async, nothing is displayed until this method finishes
      // If dispatch_sync then it does display and update
      result = [self computeNextValue];
      dispatch_async(dispatch_get_main_queue(), ^() {
        textView.text = result;
      });
    } // end computation
}

ビューをスクロールしようとするまで、これは実際にはそれほど問題ではありませんでした。痛いほど遅い。そこで、UITextView を定期的にスクロールする NSTimer を作成しました。ただし、タイマーがポップし、スクロールを要求するメソッドが実行されても、バックグラウンド メソッドが完了するまで UITextView はスクロールしません。

4

3 に答える 3

0

まず、ブロック内で self ではなく weakSelf を使用していることを確認してください。

__weak MyClass weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^() {
    [weakSelf v2]; 
});

...

__weak MyClass weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^() {
  weakSelf.textView.text = result;
});

しかし、それによって更新が遅れることはありません。キューの優先度 DISPATCH_QUEUE_PRIORITY_LOW が非常に疑わしいです。代わりに DISPATCH_QUEUE_PRIORITY_DEFAULT を使用してみてください。

于 2013-07-12T00:06:13.107 に答える
0

少なくとも経験的には、私はそれを理解したと思います。

UITextView にテキストを設定するか、プログラムでスクロールを開始すると、別のスレッドで実行されるアニメーション シーケンスがセットアップされるようです。起こっているように見えるのは、UITextView のテキストを設定する要求が、UITextView がアニメーションを設定する能力よりも速く入ってくることです。プロパティが再び変更されると、別のスレッドで設定していた以前のアニメーションが明らかにキャンセルされます。変更要求が殺到し続けているため、「テキスト」の値が再び変更される前に、やりたいことを完了することはできません。

私のソリューションには複数のステップが含まれます。

私の最初のアプローチでは、 textView.text を非常に迅速に新しい値に設定していました。UITextView のスクロールを定期的に要求するタイマーを設定しました。私の変更では、結果の文字列の新しい値を計算しますが、UITextView には設定しません。代わりに、テキストはタイマーに基づいて定期的に textview に設定されます。これにより、テキスト ビューが追いつくことができます。

しかし、これはまだ信頼できないことに気付きました。スクロール中にテキストを再度設定すると、スクロールが非常に遅くなるなど、奇妙な効果が発生します。スクロールアニメーションとテキストの繰り返し設定はまだ問題を引き起こしていたようです.

この問題を解決するには、ビューがスクロールしているかどうかを示すプロパティを作成しました。ビュー コントローラーを UITextField デリゲートとして設定します。ビューにスクロールを要求するときは、スクロールを示すフラグを設定します。まだスクロールしていない場合にのみ、コンテンツを更新してスクロールを要求します。うまくいきます。タイマーをどれだけ速く設定しても、適切に待機します。

// ViewController.h
@property BOOL isViewScrolling;

// ViewController.m
// initialize property in viewDidLoad
- (void)viewDidLoad {
  self.isViewScrolling = FALSE;
  textView.delegate = self;
  self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(scrollIt) userInfo:nil repeats:TRUE];
}

- (void)scrollIt {
  NSLog(@"scrollit thread=%d", [[NSThread currentThread]isMainThread]);
  if (!self.isViewScrolling) {
    textView.text = self.result;
    NSRange range = NSMakeRange(textView.text.length - 1, 1);
    self.isViewScrolling = TRUE;
    [textView scrollRangeToVisible:range];
  }
}

// UITextView delegate
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
  NSLog(@"Animation stopped");
  self.isViewScrolling = FALSE;
}
于 2013-07-12T01:44:35.710 に答える