ユーザーの選択に基づいて、数百の小さな PDF をダウンロードする必要があるアプリがあります。私が直面している問題は、毎回新しい接続を開く必要があるため、かなりの時間がかかっていることです。GCD を使用して非同期ダウンロードを実行できることはわかっていますが、これを 10 個程度のファイルのバッチで行うにはどうすればよいでしょうか。すでにこれを行うフレームワークはありますか、それとも自分で構築しなければならないものですか?
6 に答える
この回答は現在廃止されています。これNSURLConnection
は廃止され、NSURLSession
利用可能になりました。これは、一連のファイルをダウンロードするためのより優れたメカニズムを提供し、ここで検討されているソリューションの複雑さの多くを回避します。について説明している他の回答を参照してくださいNSURLSession
。
歴史的な目的のために、この回答を以下に残しておきます。
これには素晴らしい解決策がたくさんあると思いますが、私は、大量のファイルをダウンロードしたいというこのシナリオを処理するために、小さなダウンローダー マネージャーを作成しました。個々のダウンロードをダウンロード マネージャーに追加するだけで、1 つのダウンロードが終了すると、キューに入れられた次のダウンロードが開始されます。同時に実行する数を指定できるため (デフォルトでは 4 つ)、バッチ処理は必要ありません。他に何もないとしても、これは、独自の実装でこれを行う方法についていくつかのアイデアを引き起こす可能性があります。
これには 2 つの利点があります。
ファイルが大きい場合、これはファイル全体をメモリに保持するのではなく、ダウンロード中に永続ストレージにストリーミングします。これにより、ダウンロード プロセスのメモリ フットプリントが大幅に削減されます。
ファイルがダウンロードされている間、ユーザーまたはダウンロードの進行状況を通知するデリゲート プロトコルがあります。
ダウンロード マネージャー github ページのメイン ページで、関連するクラスと適切な操作について説明しようとしました。
ただし、これは特定の問題を解決するために設計されたものであり、大きなファイルのダウンロードの進行状況をダウンロード中に追跡し、全体を一度にメモリに保持したくないという問題を解決するために設計されたものです。 (たとえば、100 MB のファイルをダウンロードしている場合、ダウンロード中に RAM に保持したいですか?)。
私のソリューションはこれらの問題を解決しますが、それが必要ない場合は、オペレーション キューを使用したはるかに簡単なソリューションがあります。実際、あなたはこの可能性をほのめかしています:
GCD を使用して非同期ダウンロードを実行できることはわかっていますが、これを 10 個程度のファイルのバッチで行うにはどうすればよいでしょうか。...
バッチでダウンロードしてダウンロードのパフォーマンスの問題を軽減しようとするのではなく、非同期ダウンロードを行うことが適切な解決策であると言わざるを得ません。
GCD キューの使用について話します。個人的には、必要な同時操作の数を指定できるように操作キューを作成し、NSData
methodのdataWithContentsOfURL
後に を使用して個々のファイルをダウンロードしwriteToFile:atomically:
、各ダウンロードを独自の操作にするだけです。
たとえば、ダウンロードするファイルの URL の配列があると仮定すると、次のようになります。
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 4;
for (NSURL* url in urlArray)
{
[queue addOperationWithBlock:^{
NSData *data = [NSData dataWithContentsOfURL:url];
NSString *filename = [documentsPath stringByAppendingString:[url lastPathComponent]];
[data writeToFile:filename atomically:YES];
}];
}
素敵でシンプル。また、設定queue.maxConcurrentOperationCount
することで、同時要求が多すぎてアプリ (またはサーバー) を圧迫することなく、同時実行を楽しむことができます。
また、操作が完了したときに通知を受ける必要がある場合は、次のようにすることができます。
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 4;
NSBlockOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self methodToCallOnCompletion];
}];
}];
for (NSURL* url in urlArray)
{
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSData *data = [NSData dataWithContentsOfURL:url];
NSString *filename = [documentsPath stringByAppendingString:[url lastPathComponent]];
[data writeToFile:filename atomically:YES];
}];
[completionOperation addDependency:operation];
}
[queue addOperations:completionOperation.dependencies waitUntilFinished:NO];
[queue addOperation:completionOperation];
これは同じことを行いmethodToCallOnCompletion
ますが、すべてのダウンロードが完了するとメイン キューが呼び出されます。
すべての PDF が制御しているサーバーから送信されている場合、1 つのオプションは、必要なファイルのリストを (URL のクエリ パラメーターとして) 単一の要求で渡すことです。次に、サーバーは要求されたファイルを単一のファイルに圧縮できます。
これにより、必要な個々のネットワーク リクエストの数が削減されます。もちろん、このようなリクエストを処理するにはサーバーを更新する必要があり、アプリは返されたファイルを解凍する必要があります。しかし、これは、多数の個々のネットワーク リクエストを作成するよりもはるかに効率的です。
NSOperationQueue を使用して、各ダウンロードを個別の NSOperation にします。キューの最大同時操作プロパティを、同時に実行できるダウンロードの数に設定します。個人的には4~6の範囲にとどめておきます。
これは、並行操作を行う方法を説明する優れたブログ投稿です。 http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/
「構築」するものは何もありません。10 個のスレッドで毎回次の 10 個のファイルをループし、スレッドが終了したときに次のファイルを取得します。