9

次の状況を想像してみてください: バックグラウンド タスク (ここでの「タスク」という用語は、NSTask ではなく、ランダムな計算単位を意味します) があり、Grand Central Dispatch や Operation Queues などの最新のテクノロジを使用して実装されています。メイン スレッドの一部のコントローラー オブジェクトは、このバックグラウンド タスクの進行状況を監視し、それをユーザーに報告したいと考えています。

タスクの進行状況には、次の特徴があります。

  • コントローラ オブジェクトは、NSProgressIndicator を適切なスタイルに切り替えるタイミングを認識している必要があるためです
    実際の進行状況の値がゼロから増加するまで、進行状況が不確定なものとして扱われるという規則を使用できます。
  • 進捗値自体
    単純な float 値
  • ユーザーとのコミュニケーションが良好であるため、現在のフェーズの NSString のローカライズされた説明

最も Cocoa らしく、これらの要件に最適なデザインはどれですか?

バリアントが存在する可能性があります。

委任

タスクを起動する前に、コントローラー オブジェクトをデリゲートとして設定します。

@protocol MyBackgroundTaskDelegate
@required
- (void) progress: (float) value; // 0.0…1.0
@optional
- (void) workingOn: (NSString*) msg; // @"Doing this, doing that…"
@end

実際、このテンプレートを何度も使用して成功しましたが、少し冗長すぎるように感じます。

コールバックをブロックする

委任に非常に似ていますが、コードを 1 か所に保持します。

// Starting our background task...
[MyTask startComputationWithProgressHandler: ^(float progress, NSString* msg)
{
    // Switching to the main thread because all UI stuff should go there...
    dispatch_async(dispatch_get_main_queue(), ^()
    {
        self.progressIndicator.progress = progress;
        self.informationalMessage = msg;
    });
}];

KVO または進捗プロパティのポーリング

この場合、バックグラウンド タスク オブジェクトには、次のような 2 つのプロパティが必要です。

@property(readonly, atomic) float progress;
@property(readonly, atomic) NSString* message;

クライアント (コントローラー オブジェクト) は、これらのプロパティのオブザーバーとして自分自身を設定する必要があります。このソリューションで見られる主な欠陥は、KVO 通知が、変更を引き起こした同じスレッドに常に到着することです。オブザーバー (コールバック) メソッドを特定の GCD キューで強制的に実行することはできますが、常に適切であるとは限りません。

NSNotificationCenter

バックグラウンド タスクが通知を送信し、クライアントが通知をリッスンします。

この状況に適用できる他のパターンはありますか? 最もモダンで Cocoa っぽいものとして扱うことができるソリューションはどれですか?

4

4 に答える 4

2

バックグラウンドタスクの進行状況を監視するCocoaの方法とは何ですか? ブロックと KVO は後で導入されたため、デリゲーションと NSNotificationCenter と言えます。そのため、最初の Cocoa コードが書かれた年には存在しませんでした。実際、以前のバージョンの objc にもオプションのプロトコル メソッドは存在せず、すべてがデフォルトで必要でした。

ここから、ブロックはアドホック デリゲートを実装するためのより簡単な方法であることが実際にわかります。ブロックの受信者は、ブロックに渡されるパラメーターを宣言し、ブロック内でそれらを自由に使用できます。そして、KVO は、プロパティに対するより標準化されたアプローチを使用して NSNotification を実装する定型的な方法ではないようで、以前は Interface Bilder と呼ばれていたもので作成された UIに参加するのに役立ち、 「これがいつ起こるかを知るために一体何をしなければならないのか」を簡素化します。値の変更」には、NSNotification と長い定数に関する多くのドキュメントが必要です。

しかし、これらのテクニックにはそれぞれの場所があると思います: ブロックはミニアドホックプロトコルには適していますが、中程度以上のインターフェース領域または双方向インターフェースが必要な場合は深刻な問題になり、KVO は監視に役立ちません。クラス/オブジェクト外のグローバル変数または値、またはパブリック インターフェイスの一部にしたくないもの。

したがって、私の決定的な答えは次のとおりです。

  • 1対1の簡易通信:ブロック
  • 1 対 1 の複雑な通信: デリゲート/プロトコル
  • 1 対多の簡単なコミュニケーション: KVO (可能な場合)
  • 1 対多の複雑な通信: NSNotifications

いつものように、各問題に最適なツールを選択してください。上記のすべてを提案された方法で実装していないことを考慮してください。

于 2012-10-04T23:11:42.710 に答える
1

NSNotificationCenterあなたが説明するタスクのタイプについては、それが一般的なパターンの最良のオプションだと思います。その理由は、一般的に、外部のオブザーバーが何人いるかを知ることができないためです。通知システムは、イベントに対して任意の数のオブザーバーをすでにサポートしていますが、他の非ポーリングオプション(委任とブロック)は、複数の登録をサポートするために追加の作業を行わない限り、通常は1対1です。

あなたが自分自身を指摘したように、あなたがそれを避けることができれば、ポーリングは悪い考えです。

于 2012-10-11T01:13:18.050 に答える
0

私の経験では、委譲またはブロック コールバックが最良の設計選択です。どちらを選択するかは、主に、特定の状況でのコーディングとサポートにどちらが便利かによって決まります。どちらも非同期です。ブロックはスコープ内の変数をキャプチャするため、通常、ブロック コールバックは追加のインスタンス変数の必要性を減らします。もちろん、どちらの場合も、コールバックが実行されるスレッドまたはデリゲート メソッドが呼び出されるスレッドを認識する必要があります。

于 2012-10-04T18:38:53.543 に答える
0

基本的に@propertiesを使用すると無料で入手できるので、KVOを使用します。ただし、プレーンな KVO の使用はお勧めしません。それは常に呼び出されるためです-observerValueOfKeyPath ...そして、複数のキーパスを観察すると、維持するのが面倒になります。あなたはたくさんのif(keyPath == bla)を備えたこのメガ関数を持っています......

これには、MikeAsh の MAKVONotificationCenter をお勧めします。また、オブザーバーが不要になったときにオブザーバーを削除するのを忘れたときに発生する多くのクラッシュからも解放されます。

于 2012-11-14T00:26:38.200 に答える