6

NSProgressを使用して、iOS アプリでのファイル ダウンロードの進行状況を伝えています。これは非常に汎用的なクラスであり、特に 2 つの補完処理プロパティを使用することで、その固有の力に少し恐怖を覚えます。キャンセル用と一時停止用があります(ただし、完了用はありません。これはおそらくヒットです…)

これらのハンドラーは何を目的としていますか? ダウンロードを行うコードは、これらにロジックを配置して、ユーザーが開始したキャンセルと一時停止を処理できます。ただし、クライアントがハンドラーを UI コードで上書きするのを止めるものは何もありません。

それで、それはUIを対象としていますか?とにかく UI がキャンセルまたは一時停止を開始するため、これがどのように役立つパターンなのかはわかりません。また、progress オブジェクトを使用して複数の UI 要素の進行状況を同時に表示する場合 (MacOS で使用される方法)、さまざまな UI 要素がすべて独自の完了ハンドラーを必要とする可能性があります。

ハンドラーを使用してユーザー アクションをダウンロード コントローラーに伝えるのが最も便利なパターンのように思えますが、その場合、初期化時にハンドラーがセットアップされ、その後は読み取り専用のままであることが予想されます。

ここで何が欠けていますか?

(PS 今のところ、これらのハンドラーを使用せず、KVO に依存するつもりはありません。ただし、クラスの背後にあるいくつかの基本的なアイデアを見逃していると感じています)

4

2 に答える 2

1

あなたが見逃している鍵は、NSProgressクラスが進捗オブジェクトのツリーとして使用されるように設計されていることだと思います。さらに、このツリーは、親にアタッチされていることを認識する必要のない子の進行状況オブジェクトを使用して暗黙的に作成されます。これが真の力の源です。

OS X Foundation のリリース ノートは、次のクラス リファレンスよりもはるかに役立つことがわかりましたNSProgress

https://developer.apple.com/library/Mac/releasenotes/Foundation/RN-Foundation/index.html

ハンドラーが UI コントローラー ロジックとデータ コントローラー ロジックの両方に使用できるように見える理由は、親子階層を構築すると、両方に使用できる 2 つのハンドラー セットがあるためです。親のハンドラーは UI コントローラー レベル (進行状況の「コンシューマー」) で設定され、子のハンドラーはデータ コントローラー (「プロバイダー」) によって設定されます。

子の進行状況オブジェクトを使用して暗黙的に関係を作成できるため、becomeCurrentWithPendingUnitCount:親から隔離されます。これにより、クライアントがデータレベルのハンドラーを独自のもので上書きするという懸念が軽減されます。

pause進行中のオブジェクトでorを呼び出すcancelと、その呼び出しがツリーに伝搬され、途中でハンドラーが呼び出されます。

例:

// UI controller level, probably a UIViewController subclass.
- (void)handleDoSomethingButtonTapped:(UIButton *)sender
{
    self.progressThatWeObserve =
        [NSProgress progressWithTotalUnitCount:100]; // 100 is arbitrary
    self.progressThatWeObserve.pausingHandler = ^{
        // Update UI, reflect paused state ...
    };

    [self.progressThatWeObserve becomeCurrentWithPendingUnitCount:100];
    [self.dataController doSomethingInBackgroundWithCompletionHandler:^{
        // Update UI, remove from view ...
    }];
    [self.progressThatWeObserve resignCurrent];
}

// Data controller level, a SomethingManager class maybe.
- (void)doSomethingInBackgroundWithCompletionHandler:(void (^)(void)completionHandler
{
    self.progressThatWeManipulate =
        [NSProgress progressWithTotalUnitCount:289234]; // e.g. bytes to upload
    self.progressThatWeManipulate.pausingHandler = ^{
        // Actually suspend the network operation ...
    };

    dispath_async(self.workerQueue, ^{
        // Periodically update progress
    });
}

私は実際にこれを行っていないことに注意してください。これはすべて、ドキュメントを読んだことによる理論です。

于 2014-02-21T01:32:11.743 に答える