1

データモデルからの情報をユーザーインターフェイスに表示しています。そうするための私の現在のアプローチは、次のような委任によるものです。

@protocol DataModelDelegate <NSObject>
- (void)updateUIFromDataModel;
@end

GCDを使用してUIの更新をメインスレッドにプッシュし、コントローラークラスにデリゲートメソッドを次のように実装しています。

- (void)updateUIFromDataModel {

    dispatch_async(dispatch_get_main_queue(), ^{

        // Code to update various UI controllers
        // ...
        // ...

    });
}

私が懸念しているのは、状況によっては、このメソッドが非常に頻繁に呼び出される可能性があることです(1秒あたり約1000回、それぞれが複数のUIオブジェクトを更新します)。これは、コマンドでメインスレッドを「スパム」しているように感じます。

これはメインスレッドに送信するには多すぎますか?もしそうなら、誰かがこれにアプローチするための最良の方法は何であるかについて何かアイデアを持っていますか?

私は調べましdispatch_applyたが、データを合体するときにもっと便利なようですが、これは私が求めているものではありません-更新が頻繁すぎる場合は更新をスキップしたいので、かなりの量の更新のみがメインスレッドに送信されます!

別のアプローチを取り、代わりにタイマーを実装して、たとえば10ミリ秒ごとにデータを常にポーリングすることを検討していましたが、データの更新は散発的になる傾向があるため、そうするのは無駄だと感じています。

両方のアプローチを組み合わせて、私が検討した別のオプションは、更新メッセージを待って、設定された間隔でデータをポーリングするようにタイマーを設定し、データの変更が停止したように見える場合はタイマーを無効にすることで応答することです。しかし、これは問題を過度に複雑にするのでしょうか。また、適切なアプローチは、単に一定のタイマーを実行することでしょうか。

編集: ディスパッチソースを使用した適応を示す以下の回答を追加しました

4

3 に答える 3

7

1 つのオプションは、イベントを繰り返し投稿し、libdispatch にそれらを結合させることができるタイプのDispatch Sourceを使用することです。DISPATCH_SOURCE_TYPE_DATA_OR投稿するものがあるときは、dispatch_source_merge_data何か新しいことがあることを知らせるために使用します。ターゲット キュー (この場合はメイン キュー) がビジー状態の場合、複数の呼び出しdispatch_source_merge_dataが合体されます。

于 2013-03-19T16:44:53.230 に答える
5

私はディスパッチソースを実験しており、期待どおりに機能するようになりました-この質問に出くわした人に役立つ場合に備えて、クラスの実装をどのように適応させたかを次に示します。

@implementation AppController {
@private
    dispatch_source_t _gcdUpdateUI;
}

- (void)awakeFromNib {

    // Added the following code to set up the dispatch source event handler:

    _gcdUpdateUI = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, 
                                          dispatch_get_main_queue());
    dispatch_source_set_event_handler(_gcdUpdateUI, ^{

        // For each UI element I want to update, pull data from model object:
        // For testing purposes - print out a notification:
        printf("Data Received. Messages Passed: %ld\n", 
               dispatch_source_get_data(_gcdUpdateUI));
    });

dispatch_resume(_gcdUpdateUI);

}

次に、デリゲート メソッドで への呼び出しを削除dispatch_asyncし、次のように置き換えました。

- (void)updateUIFromDataModel {

  dispatch_source_merge_data(_gcdUpdateUI, 1);

}

これは私にとってはまったく問題なく機能しています。今では、最も集中的なデータ更新中であっても、UI は完全に応答性を保ちます。

出力は合体が機能しているかどうかを確認するための非常に大雑把な方法でしたがprintf()、コンソール出力をすばやくスクロールして戻ると、出力されたメッセージの大部分が値 1 (簡単に 98%) であることがわかりました。断続的に約 10 ~ 20 に跳ね上がり、モデルが最も多くの更新メッセージを送信していた頃に 100 を超える合体メッセージのピーク値に達しました。

助けてくれてありがとう!

于 2013-03-19T21:38:49.103 に答える
2

アプリが重い負荷の下でビーチボールをする場合は、メイン スレッドを長時間ブロックしているため、UI 更新のための合体戦略を実装する必要があります。アプリがクリックに対する応答性を維持し、ビーチ ボールを行わない場合は、問題ありません。

于 2013-03-19T15:51:58.133 に答える