1. 使用 AFHTTPRequestOperation 实现断点续传的代码
// 1 指定下载文件地址 URLString
// 2 获取保存的文件路径 filePath
// 3 创建 NSURLRequest
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:URLString]];
unsigned long long downloadedBytes = 0;
if([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
// 3.1 若之前下载过 , 则在 HTTP 请求头部加入 Range
// 获取已下载文件的 size
downloadedBytes = [self fileSizeForPath:filePath];
// 验证是否下载过文件
if(downloadedBytes > 0) {
// 若下载过 , 断点续传的时候修改 HTTP 头部部分的 Range
NSMutableURLRequest *mutableURLRequest = [request mutableCopy];
NSString *requestRange =
[NSString stringWithFormat:@"bytes=%llu-", downloadedBytes];
[mutableURLRequest setValue:requestRange forHTTPHeaderField:@"Range"];
request = mutableURLRequest;
}
}
// 4 创建 AFHTTPRequestOperation
AFHTTPRequestOperation *operation
= [[AFHTTPRequestOperation alloc] initWithRequest:request];
// 5 设置操作输出流 , 保存在第 2 步的文件中
operation.outputStream = [NSOutputStream
outputStreamToFileAtPath:filePath append:YES];
// 6 设置下载进度处理 block
[operation setDownloadProgressBlock:^(NSUInteger bytesRead,
long long totalBytesRead, long long totalBytesExpectedToRead) {
// bytesRead 当前读取的字节数
// totalBytesRead 读取的总字节数 , 包含断点续传之前的
// totalBytesExpectedToRead 文件总大小
}];
// 7 设置 success 和 failure 处理 block
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation
*operation, id responseObject) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
// 8 启动 operation
[operation start];
2. NSURLConnection 的实现
// 请求失败处理
func connection(connection: NSURLConnection,
didFailWithError error: NSError) {
self.failureHandler(error: error)
}
// 接收到服务器响应是调用
func connection(connection: NSURLConnection,
didReceiveResponse response: NSURLResponse) {
ifself.totalLength != 0 {
return
}
self.writeHandle = NSFileHandle(forWritingAtPath:
FileManager.instance.cacheFilePath(self.fileName!))
self.totalLength = response.expectedContentLength + self.currentLength
}
// 当服务器返回实体数据是调用
func connection(connection: NSURLConnection, didReceiveData data: NSData) {
let length = data.length
// move to the end of file
self.writeHandle.seekToEndOfFile()
// write data to sanbox
self.writeHandle.writeData(data)
// calculate data length
self.currentLength = self.currentLength + length
print("currentLength\(self.currentLength)-totalLength\(self.totalLength)")
if(self.downloadProgressHandler != nil) {
self.downloadProgressHandler(bytes: length, totalBytes:
self.currentLength, totalBytesExpected: self.totalLength)
}
}
// 下载完毕后调用
func connectionDidFinishLoading(connection: NSURLConnection) {
self.currentLength = 0
self.totalLength = 0
//close write handle
self.writeHandle.closeFile()
self.writeHandle = nil
let cacheFilePath = FileManager.instance.cacheFilePath(self.fileName!)
let documenFilePath = FileManager.instance.documentFilePath(self.fileName!)
do{
tryFileManager.instance.moveItemAtPath(cacheFilePath, toPath: documenFilePath)
} catchlet e as NSError {
print("Error occurred when to move file: \(e)")
}
self.successHandler(responseObject:fileName!)
}
3.NSURLSessionDataTask 的实现
// 接收数据
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask,
idReceiveData data: NSData) {
//. . .
}
// 接收服务器响应
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask,
didReceiveResponse response: NSURLResponse, completionHandler:
(NSURLSessionResponseDisposition) -> Void) {
// . . .
completionHandler(.Allow)
}
// 请求完成
func URLSession(session: NSURLSession, task: NSURLSessionTask,
didCompleteWithError error: NSError?) {
iferror == nil {
// . . .
self.successHandler(responseObject:self.fileName!)
} else{
self.failureHandler(error:error!)
}
}
4. NSURLSessionDownloadTask 的实现
//UI 触发 pause
func pause(){
self.downloadTask?.cancelByProducingResumeData({data -> Void in
ifdata != nil {
data!.writeToFile(FileManager.instance.cacheFilePath(self.fileName!),
atomically: false)
}
})
self.downloadTask = nil
}
// MARK: - NSURLSessionDownloadDelegate
func URLSession(session: NSURLSession, downloadTask:
NSURLSessionDownloadTask, didWriteData bytesWritten: Int64,
totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
if(self.downloadProgressHandler != nil) {
self.downloadProgressHandler(bytes: Int(bytesWritten),
totalBytes: totalBytesWritten, totalBytesExpected: totalBytesExpectedToWrite)
}
}
func URLSession(session: NSURLSession, task: NSURLSessionTask,
didCompleteWithError error: NSError?) {
iferror != nil {//real error
self.failureHandler(error:error!)
}
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask,
didFinishDownloadingToURL location: NSURL) {
let cacheFilePath = FileManager.instance.cacheFilePath(self.fileName!)
let documenFilePath = FileManager.instance.documentFilePath(self.fileName!)
do{
ifFileManager.instance.fileExistsAtPath(cacheFilePath){
tryFileManager.instance.removeItemAtPath(cacheFilePath)
}
tryFileManager.instance.moveItemAtPath(location.path!, toPath: documenFilePath)
} catchlet e as NSError {
print("Error occurred when to move file: \(e)")
}
self.successHandler(responseObject:documenFilePath)
}
可以参考一个作者写的GitHub搜索KillAppDownload,进行了充分的缓存
参考文章写得很不错 http://www.cocoachina.com/ios/20160728/17219.html