0

現在、ファイルダウンロードアプリケーションを実装しています。アプリケーション サーバーには約 2500 個のリソース ファイルがあり、サーバーからドキュメント ディレクトリにこれらのファイルをダウンロードする必要があります。

私のコード:

@implementation DownloadManager
{
    NSURLSession *session;
    BOOL downloading;
}

#pragma mark - NSURLSessionDownloadDelegate

// Handle download completion from the task
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
    NSInteger index = [self assetDownloadIndexForDownloadTask:downloadTask];
    if (index < 0)
    {
        return;
    }
    DownloadHelper *movieDownload = _assetsToDownload[index];

    // Copy temporary file
    NSError * error;
    [[NSFileManager defaultManager] copyItemAtURL:location toURL:[NSURL fileURLWithPath:[movieDownload localPath]] error:&error];
    downloading = NO;
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{
    // Required delegate method
}

// Handle task completion
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    if (error)
        NSLog(@"Task %@ failed: %@", task, error);
    NSLog(@"Task %@ Success: %@", task, error);
    if ([_assetsToDownload count])
    {
        [_assetsToDownload removeObjectAtIndex:0];
    }

    downloading = NO;
    if ([_assetsToDownload count])
    {
        [self downloadFiles];
    }
    else
    {
        [self downloadAssets];
    }
}

// Handle progress update from the task
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    NSInteger index = [self assetDownloadIndexForDownloadTask:downloadTask];
    if (index < 0) return;
   // DownloadHelper *movieDownload = _assetsToDownload[index];
    double progress = (double) (totalBytesWritten/1024) / (double) (totalBytesExpectedToWrite/1024);
    dispatch_async(dispatch_get_main_queue(), ^{
        // Showing progress
    });

}

#pragma mark - Movie Download Handling & UI

// Helper method to get the index of a Asset from the array based on downloadTask.
- (NSInteger)assetDownloadIndexForDownloadTask:(NSURLSessionDownloadTask *)downloadTask
{
    NSInteger foundIndex = -1;
    NSInteger index = 0;
    for (DownloadHelper *asset in _assetsToDownload)
    {
        if (asset.downloadTask == downloadTask)
        {
            foundIndex = index;
            break;
        }
        index++;
    }
    return foundIndex;
}

- (void)addAssetDownload
{
    DownloadInfo *info = nil;
    NSString *assetFolder = nil;
    for (int index = 0; index<[_assets count]; index++)
    {
        info                                    = [_assets objectAtIndex:index];
        NSURL *url                              = [NSURL URLWithString:info.assetURL];
        NSURLRequest *request                   = [NSURLRequest requestWithURL:url];
        NSURLSessionDownloadTask *downloadTask  = [session downloadTaskWithRequest:request];

        DownloadHelper *assetDownload        = [[DownloadHelper alloc] initWithURL:url downloadTask:downloadTask];
        assetDownload.assetName                 = info.assetName;

        if (info.categoryId == 1)
        {
            assetFolder = [self getImagePath:info.assetName];
        }
        else if (info.categoryId == 2)
        {
            assetFolder = [self getVideoPath:info.assetName];
        }
        else if (info.categoryId == 3)
        {
            //assetFolder = [self getDBPath:info.assetName];
        }
        else
        {
            assetFolder = [self filePath:info.assetName];
        }
        assetDownload.assetFolder = assetFolder;
        [_assetsToDownload addObject:assetDownload];
    }
}

// Initialize the download, session and tasks
- (void)initialize
{
    for (DTEDownloadHelper *movieDownload in _assetsToDownload)
    {
        // Cancel each task
        NSURLSessionDownloadTask *downloadTask = movieDownload.downloadTask;
        [downloadTask cancel];
    }

    // Cancel all tasks and invalidate the session (also releasing the delegate)
    [session invalidateAndCancel];
    session = nil;

    _assetsToDownload = [[NSMutableArray alloc] init];

    // Create a session configuration passing in the session ID
    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"DTEDownloadBackground"];
    sessionConfiguration.discretionary = YES;
    session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
    [self addAssetDownload];
    // Reset the UI
    downloading = NO;
    [self downloadFiles];

}


// Download handler
- (void)downloadFiles
{
    if ([_assetsToDownload count] > 0)
    {
        // Acquire the appropriate downloadTask and respond appropriately to the user's selection
        NSURLSessionDownloadTask * downloadTask = [_assetsToDownload[0] downloadTask];
        if (downloadTask.state == NSURLSessionTaskStateCompleted)
        {
            // Download is complete.  Play movie.
            // NSURL *movieURL = [NSURL fileURLWithPath:[_assetsToDownload[0] localPath]];
        }
        else if (downloadTask.state == NSURLSessionTaskStateSuspended)
        {
            // If suspended and not already downloading, resume transfer.
            if (!downloading)
            {
                [self showHUD:[NSString stringWithFormat:@"Downloading %@",[_assetsToDownload[0] assetName]]];
                [downloadTask resume];
                downloading = YES;
            }
        }
        else if (downloadTask.state == NSURLSessionTaskStateRunning)
        {
            // If already downloading, pause the transfer.
            [downloadTask suspend];
            downloading = NO;
        }

    }
}

- (void)downloadAssets
{
    _assets = [self retreiveAssets];    // Getting the resource details from the database
    if (![_assets count])
    {
        // Hide progress
    }
    [self addAssetDownload];
    [self downloadFiles];
}
@end

問題 :

最初のファイルをダウンロードしてそこで停止する場合があり、次回以降は何もダウンロードされません。今まで問題を見つけることができませんでした。この問題のためにほぼ 1 日を無駄にしました。問題を見つけるのを手伝ってください。前もって感謝します。

4

2 に答える 2

3

バックグラウンド セッションを使用している場合、古いダウンロード リクエストがセッション間で持続する可能性があります。古い未処理のバックグラウンド タスクを でチェックしてみましたgetTasksWithCompletionHandlerか? アプリの起動時に、古いバックグラウンド リクエストの背後でバックログが発生する可能性があることに気付くまで、しばらく時間がかかりました。また、そのバックグラウンド セッションに無効なリクエストがある場合は、すべてが少しバックアップされる可能性があります。

また、アプリのデリゲートはhandleEventsForBackgroundURLSessionメソッドを処理し、バックグラウンド セッションを再インスタンス化completionHandlerし、アプリに渡されたものを保存していますか? そして、その完了ハンドラーを呼び出すのはdelegateNSURLSessionおそらくURLSessionDidFinishEventsForBackgroundURLSession:メソッド内で)ですか?これらのバックグラウンド セッションを確実にクリーンアップする必要があります。コード スニペットにこのメソッドはありませんが、簡潔にするために省略した可能性があります。

これに関する議論は、 URL Loading System Programming Guide: Using NSURLSessionガイドのBackground Transfer Considerationsセクションにあります。また、この例は、WWDC 2013 What's New in Foundation Networkingビデオの約 40 分後に表示されます。

于 2014-06-11T16:49:40.023 に答える
0

使用NSURLSessionDownloadTaskは私にとって混乱でした。最後に、 と を使用してカスタム ダウンロード マネージャーを実装しましNSOperationQueueblocks

このライブラリをGitHubに追加しました。

于 2014-07-05T16:48:37.070 に答える