处于更高的高度来理解文件下载,它和获取数据有点儿类似。我们的app需要实现以下(NSURLSessionDownloadDelegate)代理方法:

对于第一点:在该方法返回之前,它为了读取这个文件必须要打开该文件,或者移动该文件到常驻的位置。当该方法返回之后,如果该文件依然存在于原来的位置,那么该文件将会被删除。

如果在后台session中添加了下载任务,在app进入暂停状态之后,该任务依然会继续执行。如果是在默认的session和短暂的session中添加的下载任务,那么它们在程序重启之后会从头开始执行。

断点下载逻辑

当在服务器数据传输过程中,如果用户要求app暂停下载,我们在程序中可以调用cancelByProducingResumeData:方法来取消该任务。在后面的某个时刻,我们可以把返回的resumedata(因为cancelByProducingResumeData:方法的返回变量就叫resumeData,这里放入原文更好理解,故不进行翻译)传递给downloadTaskWithResumeData:方法 或者downloadTaskWithResumeData:completionHandler:方法中的任意一个去创建一个新的下载任务以继续之前的下载

断点下载并不是之前的task中,而是新创建了一个任务。

传输失败的情况处理

如果传输失败,代理方法URLSession:task:didCompleteWithError: 会被调用,并传递给我们一个NSError对象。如果这个任务是可以继续的(也就是可以继续下载的),该NSError对象的userInfo字典会包含一个以NSURLSessionDownloadTaskResumeData为key的值,我们可以传递返回的resumeData给downloadTaskWithResumeData:方法或者downloadTaskWithResumeData:completionHandler:方法中的任意一个去创建一个新的下载任务以继续之前的下载。

[error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData]

样例

下面展示了下载大文件的例子:

/// Objective-C
NSURL *url = [NSURL URLWithString:@"https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/ObjC_classic/FoundationObjC.pdf"];
NSURLSessionDownloadTask *downloadTask = [backgroundSession downloadTaskWithURL:url];
[downloadTask resume];
/// 代理
- (void)URLSession:(NSURLSession *)session
      downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
 totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    NSLog(@"Session %@ download task %@ wrote an additional %lld bytes (total %lld bytes) out of an expected %lld bytes.\n", session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
}

- (void)URLSession:(NSURLSession *)session
      downloadTask:(NSURLSessionDownloadTask *)downloadTask
 didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
{
    NSLog(@"Session %@ download task %@ resumed at offset %lld bytes out of an expected %lld bytes.\n", session, downloadTask, fileOffset, expectedTotalBytes);
}

- (void)URLSession:(NSURLSession *)session
      downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
    NSLog(@"Session %@ download task %@ finished downloading to URL %@\n", session, downloadTask, location);

    // Perform the completion handler for the current session
    self.completionHandlers[session.configuration.identifier]();

   // Open the downloaded file for reading
    NSError *readError = nil;
    NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingFromURL:location error:readError];
    // ...

   // Move the file to a new URL
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSURL *cacheDirectory = [[fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] firstObject];
    NSError *moveError = nil;
    if ([fileManager moveItemAtURL:location toURL:cacheDirectory error:moveError]) {
        // ...
    }
}
///Swift
if let url = URL(string: "https://www.example.com/") {
    let dataTask = defaultSession.dataTask(with: url)
    dataTask.resume()
}
/// 代理
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
    print("Session \(session) download task \(downloadTask) wrote an additional \(bytesWritten) bytes (total \(totalBytesWritten) bytes) out of an expected \(totalBytesExpectedToWrite) bytes.\n")
}

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) {
    print("Session \(session) download task \(downloadTask) resumed at offset \(fileOffset) bytes out of an expected \(expectedTotalBytes) bytes.\n")
}

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
    print("Session \(session) download task \(downloadTask) finished downloading to URL \(location)\n")

    // Perform the completion handler for the current session
    self.completionHandlers[session.configuration.identifier]()

    // Open the downloaded file for reading
    if let fileHandle = try? FileHandle(forReadingFrom: location) {
        // ...
    }

    // Move the file to a new URL
    let fileManager = FileManager.default()
    if let cacheDirectory = fileManager.urlsForDirectory(.cachesDirectory, inDomains: .userDomainMask).first {
        do {
            try fileManager.moveItem(at: location, to: cacheDirectory)
        } catch {
            // ...
        }
    }
}

results matching ""

    No results matching ""