2

サーバーからiPhoneアプリディレクトリ(Documentsディレクトリ)に大量(800〜2000枚)の画像を保存したい。

まず、これらの画像が既に iPhone ディレクトリにあるかどうかを確認する必要があります。

このコードを使用して、1 つの画像をダウンロードします。

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://a3.twimg.com/profile_images/414797877/05052008321_bigger.jpg"]];
[NSURLConnection connectionWithRequest:request delegate:self];

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *localFilePath = [documentsDirectory stringByAppendingPathComponent:@"pkm.jpg"];
NSData *thedata = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://a3.twimg.com/profile_images/414797877/05052008321_bigger.jpg"]];
[thedata writeToFile:localFilePath atomically:YES];

アドバイスをお願いします: 1. すべての画像を「pkm.jpg」ではなく、元の名前で iPhone ディレクトリに保存します 2. 画像を次の名前で保存します: 05052008321_bigger から 05052008350_bigger まで 3. 画像が既にダウンロードされているかどうかを確認します。ダウンロードしないでくださいまた。

私は知っています、多分これは質問以上のものです。しかし、いくつかの提案、方向性は本当に良いでしょう。

前もって感謝します。

4

2 に答える 2

2

いくつかの反応:

  1. NSURLConnection connectionWithRequest(メソッドをトリガーする) を開始していますNSURLConnectionDataDelegateが、明らかにそれを無視して を開始していdataWithContentsOfURLます。どちらかを選択する必要がありますが、両方を実行しないでください。

  2. NSOperation絶対に (a) 同時実行を楽しみたいので、ベースのソリューションを追求することをお勧めします。ただし、(b) 同時操作を妥当な数 (たとえば 4 または 5) に制限します。そうしないと、リクエストがタイムアウトして失敗します。

  3. ファイル名の取得に関してはlastPathComponentNSURL. (以下で使用する私のダウンロード操作は、明示的なファイル名を指定しない場合、実際には自動的にこれを使用します。)

  4. リモート サーバーからファイル名のリストを取得する方法を説明していないので、どの画像を取得する必要があるかを知る方法を確認する必要があります。

  5. これがあなた自身の目的であれば問題ありませんが、セルラー接続で大量のデータを要求するアプリを Apple が拒否するという主張を聞いたことがあります (そして 2000 枚の画像は確かに資格があります)。率直に言って、Apple が大騒ぎしなくても、データ プランをそれほど多く使用する前に、ユーザーに尋ねる必要があります。Reachabilityを使用して、ユーザーが Wi-Fi 経由で接続しているかセルラー経由で接続しているかを判断できます。後者の場合は、警告を表示することができます。

しかし、私は次のようなものを提案したいと思います (URL のバージョンをいくつか持っていると仮定しますNSArray... NSStringURL のリストがどのような形式であっても、明らかにこれを調整します):

NSOperationQueue *downloadQueue = [[NSOperationQueue alloc] init];
downloadQueue.maxConcurrentOperationCount = 4;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];

for (NSString *urlString in urlStrings)
{
    NSURL *url = [NSURL URLWithString:urlString];
    NSString *path = [docsPath stringByAppendingPathComponent:[url lastPathComponent]];
    if (![fileManager fileExistsAtPath:path]) {
        DownloadOperation *downloadOperation = [[DownloadOperation alloc] initWithURL:url];
        downloadOperation.downloadCompletionBlock = ^(DownloadOperation *operation, BOOL success, NSError *error) {
            if (error) NSLog(@"download of %@ failed: %@", operation.url, error);
        };
        [downloadQueue addOperation:downloadOperation];
    }
}

そして、そのダウンロード操作は次のようなものかもしれませ。明らかに、必要なNSOperationベースのダウンローダーを使用しますが、ダウンロード全体をメモリにロードするのではなく、永続ストレージに直接ストリーミングするダウンローダーを使用することをお勧めします。

それほど派手にしたくない場合は、次のようにすることができます。

NSOperationQueue *downloadQueue = [[NSOperationQueue alloc] init];
downloadQueue.maxConcurrentOperationCount = 4;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];

for (NSString *urlString in urlStrings)
{
    NSURL *url = [NSURL URLWithString:urlString];
    NSString *path = [docsPath stringByAppendingPathComponent:[url lastPathComponent]];
    if (![fileManager fileExistsAtPath:path]) {
        [downloadQueue addOperationWithBlock:^{
            NSString *path = [docsPath stringByAppendingPathComponent:[url lastPathComponent]];
            NSData *data = [NSData dataWithContentsOfURL:url];
            if (data)
                [data writeToFile:path atomically:YES];
        }];
    }
}

明らかに、ダウンロードに必要なダウンロード操作クラスを使用しますが、基本的な考え方を理解していただければ幸いです。ベースのダウンロードを作成し、NSOperationダウンロードが必要なファイルごとに 1 つ送信します。

于 2013-08-12T02:46:14.123 に答える
1

情報をシリアル化する最良の方法がわかりません (単純に、NSDictionary をディスクに書き込むことができます)。私は大きな NSDictionary を持っています(それを行う方法次第で、より小さなものに分割できます)。NSDictionary は、イメージ名 "05052008321_bigger" を取得し、単純な @YES にマップします。

アプリが新しい画像をダウンロードできる状態になると、ディスクから NSDictionary を読み取り (別のスレッドで読み取ることができます)、画像名がディクショナリにあるかどうかを確認します。これにより、ルックアップが高速になります。

- (BOOL)checkIfImageHasBeenDownloaded:(NSString *)imageName
{
    return [self.dictionaryNames objectForKey:imageName] != nil;
}
于 2013-08-12T02:33:36.157 に答える