8

サーバーから何千もの画像をダウンロードするタスク (iOS5 + のみ) に取り組んでいます。画像は特定のカテゴリに属し、各カテゴリには何百もの画像が含まれる場合があります。私がする必要があるのはこれです:-

1) アプリがアクティブな場合 (ユーザーが写真に関係のないアプリの他の領域を閲覧している場合でも)、アプリが不足している画像をバックグラウンドでダウンロードすることを確認します。

2) ユーザーが写真カテゴリをクリックすると、そのカテゴリ内の画像はすぐに表示する必要があるため、優先的にダウンロードする必要があります。

上記のすべては、イメージがまだオフラインで利用できない場合にのみ発生します。ダウンロードが完了すると、イメージはローカル ストレージから使用されます。

これを解決するために、私が使用しているロジックは次のとおりです:-

1) AppDelegate.m で、applicationDidBecomeActive欠落している画像のダウンロードを開始します。これを行うには、Core Data クエリを作成し、欠落している画像を見つけて、バックグラウンド優先度のスレッドでダウンロードを開始します。このようなもの :-

 dispatch_queue_t imageDownloadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_async(imageDownloadQueue, ^{
    [DataDownloader downloadMissingImages];
});
dispatch_release(imageDownloadQueue);

コードは次のdownloadMissingImagesようになります:-

NSOperationQueue *downloadQueue = [[NSOperationQueue alloc] init];
        downloadQueue.maxConcurrentOperationCount = 20;

        for(MyImage *img in matches)
        {
            NSURLRequest *request = [NSURLRequest requestWithURL:img.photoUrl];
            AFImageRequestOperation *operation = [AFImageRequestOperation imageRequestOperationWithRequest:request success:^(UIImage *image) {

                [MyImage imageFromAPI:image inManagedObjectContext:document.managedObjectContext];

                NSLog(@"Successfully downloaded image for %@", img.title);      
            }];

            [downloadQueue addOperation:operation];
        }

これは機能しますが、メイン UI がブロックされ、しばらくするとアプリがクラッシュします。これは、約700枚の画像をダウンロードしようとしたときです。より多くの画像を使用すると、確実にクラッシュします。

2) ユーザーがカテゴリをクリックすると、すぐにユーザーに表示する必要があるため、最初にそれらの画像をダウンロードする必要があります。missingImages 呼び出しを中断して、特定の画像のダウンロードを他の画像より先に開始するように指示する方法がわかりません。

したがって、基本的には、不足しているすべての画像をバックグラウンドでダウンロードする必要がありますが、ユーザーが写真カテゴリを閲覧している場合、それらの画像はダウンロード キューで優先度を高くする必要があります。

これを効率的に機能させる方法に途方に暮れています。何かご意見は?

クラッシュログは次のようになります

PAPP(36373,0xb065f000) malloc: *** mmap(size=16777216) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
PAPP(36373,0xb065f000) malloc: *** mmap(size=16777216) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
Jun 24 11:39:45 MacBook-Pro.local PAPP[36373] <Error>: ImageIO: JPEG    Insufficient memory (case 4)

前もって感謝します。

4

1 に答える 1

3

クラッシュについては、次の2つのオプションのいずれかが原因でアプリが強制終了されたと思います。

  1. アプリが応答しなくなった(したがって、iOSセンチネルプロセスに応答しなくなった)。

  2. ループで使用されるメモリが多すぎて、700を超える要求操作が作成されます。

実際に何が起こっているのかを明確にするために、クラッシュに関する詳細情報(コンソールログ)を提供する必要があります。いずれにせよ、修正はおそらくそれぞれ10または20のチャンクで画像をロードすることです(必要に応じて、1つずつ移動することもできますが、それほど問題はありません)。

2番目のポイントについて、これはどうですか?

  1. メインスレッドで優先度の高いイメージをダウンロードします(もちろん、UIのブロックを回避するために、非同期ダウンロードを介して)。

  2. 「オフライン」イメージのダウンロードを開始する前に、「優先度の高い」ダウンロードを通じて、その間にイメージがすでにダウンロードされているかどうかを確認します。

AFImageRequestOperationポイント2を適切に処理するには、実際のダウンロードの前にチェックを実行するために、ではなくカスタム操作をキューに入れる必要があります。

編集:

画像をまとめてダウンロードする場合、ディスパッチグループを使用してネットワーク操作をグループ化することができます。

dispatch_group_t group = dispatch_group_create();

<your_core_data_query>

for (...) {
    dispatch_group_enter(group);

        NSURLRequest *request = [NSURLRequest requestWithURL:img.photoUrl];
        AFImageRequestOperation *operation = [AFImageRequestOperation imageRequestOperationWithRequest:request success:^(UIImage *image) {
            [MyImage imageFromAPI:image inManagedObjectContext:document.managedObjectContext];
            NSLog(@"Successfully downloaded image for %@", img.title);

            dispatch_group_leave(group);     //<== NOTICE THIS
        }];

}

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);

このサンプルでは、​​ディスパッチグループを使用して、いくつかの非同期操作をグループ化し、それらがすべて実行されるのを待ちます。戻ったら、dispatch_group_waitその別のラウンドを実行できます(コアデータをクエリしてからopsをディスパッチします)。

他の質問(優先度の高いキューがすでに特定のイメージをダウンロードしているかどうかを確認するにはどうすればよいですか)については、それぞれを実行する前にコアデータクエリを実行する必要がありますAFImageRequestOperation。1つの可能性は、独自のクラスを導出し、メソッドをオーバーライドstartしてチェックを実行することです。

どちらのアカウントでも、一度に1つずつ画像をダウンロードすることで、これらすべてのロジックを大幅に簡素化できます(つまり、for (...)ループは発生しません。次の画像をクエリしてダウンロードしてダウンロードします。ダウンロードする前に、画像がないことを確認します。もう着いている。

私はこのより簡単な道を行くことを提案します。

それが役に立てば幸い。

于 2012-06-24T10:28:06.493 に答える