2013-09-23 1 views
6

NSProgressを使用して、iOSアプリでのファイルのダウンロード状況を通知しています。 これは非常に汎用的なクラスであり、特に2つの補完処理プロパティでは、その本質的なパワーを少し怖がっています。キャンセルを処理するものと、一時停止するものがあります(ただし、完了していないものはおそらくヒットします...)NSProgressでは、UIまたはダウンロードコントローラ用のコンプリートハンドラはありますか?

これらのハンドラの対象は何ですか?ダウンロードを行うコードは、ユーザーが作成したキャンセルや一時停止に対処するためにロジックに入れられます。しかし、クライアントがUIコードでハンドラーを上書きするのを止めるものは何もありません。

これはUI向けのものですか? UIがキャンセルまたはポーズをとにかく発生させるので、これがどのように役立つパターンなのかよく分かりません。また、進捗オブジェクトを使用して複数のUI要素(MacOSでの使用方法)の進捗状況を同時に表示する場合、さまざまなUI要素がすべて独自の完了ハンドラを必要とする可能性があります。

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

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

(PSは、今の私は単にそれらのハンドラを使用するつもりはないとKVOに依存している。しかし、私はクラスの背後にあるいくつかの基本的な考え方を逃していかゆみ感を持っている)

+0

私はプライベートクラスのようですが、あなたはそれを使いたいですか? – Ian

+1

プライベートではありません。 [Appleの開発者のドキュメント](https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSProgress_Class/Reference/Reference.html) –

+0

私の悪い、私は存在していたことが分かりませんでした。 – Ian

答えて

1

あなたが欠けているキーは、NSProgressクラスが進捗オブジェクトのツリーとして使用されるように設計されていると思います。さらに、このツリーは、親プロセスに暗黙的に作成されます。子プロセスは、親にアタッチされていることを意識する必要はありません。

私はOS X Foundationリリースがはるかに便利NSProgressのクラス参照よりもノートが見つかりました:

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

ハンドラがUIコントローラロジックとデータコントローラロジックの両方のために使用することができると思われる理由があります親子階層を構築するときに、両方に使用できるハンドラのセットが2つあることを確認してください。親のハンドラはUIコントローラレベル(進捗の「消費者」)に設定され、子のハンドラはデータコントローラ(「プロバイダ」)によって設定されます。

becomeCurrentWithPendingUnitCount:を使用して暗黙的に関係を作成できるため、子プログレスオブジェクトは親から隔離されているため、クライアントがデータレベルハンドラを上書きする心配が軽減されます。

進捗オブジェクトのpauseまたは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 
    }); 
} 

私は実際にこののいずれかを行っていないのでご注意ください、それは、ドキュメントを読んでから、すべての理論です。

0

あなたがそれらを使用することができますあなたが望むもののためのブロック。具体的には、UIに何かしたい場合は、ドキュメントの「特別な考慮事項」に記載されているように、メインスレッド上で確実に行う必要があります。「取り消しハンドラはどのキューでも呼び出すことができます。特定のキューで作業する場合は、キャンセルハンドラブロック内からそのキューにディスパッチする必要があります。だから、UIのためにあなたが使用します。

dispatch_async(dispatch_get_main_queue(), ^{ 
    // Do work on UI 
}); 

を完了ハンドラパターンはいつも "バックグラウンドで実行されるタスクに対処するための一般的です。サーバーからファイルをダウンロードするなどのI/Oタスク。この場合、アプリケーション内にNSProgressインスタンスのpause:またはcancel:メソッドを呼び出すイベントが多数存在する可能性があるため、一時停止およびキャンセル用の単一のハンドラを定義すると便利です。

+0

それは私が*私は私が私を混乱させたいものにそれらを使用することができるという事実です。しかし、これらのブロックはバックグラウンドで呼び出される可能性があるため、UIコードを意図していない点で正しいと思います。つまり、ダウンロードロジックコードはハンドラを設定し、UIコードはそれらのハンドラを混乱させることはありません。 –

+0

そうです。ブロック内のUIで作業をしたい場合は、私の答えのように、メインスレッド(UIで混乱させるべき唯一の場所)に配置する必要があります。 – JuJoDi

関連する問題