Closed mahong125 closed 8 years ago
hey,I refer your idea to write a download manager, but does not support breakpoints download, hope you can help me analyze, be grateful.
code:
#import "DownLoadViewController.h" #import "BaseCell.h" #import <AFNetworking.h> #import "DownModel.h" #define fileDest [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/"] NSString * const kMZDownloadKeyURL = @"URL"; NSString * const kMZDownloadKeyStartTime = @"startTime"; NSString * const kMZDownloadKeyFileName = @"fileName"; NSString * const kMZDownloadKeyProgress = @"progress"; NSString * const kMZDownloadKeyTask = @"downloadTask"; NSString * const kMZDownloadKeyStatus = @"requestStatus"; NSString * const kMZDownloadKeyDetails = @"downloadDetails"; NSString * const kMZDownloadKeyResumeData = @"resumedata"; NSString * const RequestStatusDownloading = @"RequestStatusDownloading"; NSString * const RequestStatusPaused = @"RequestStatusPaused"; NSString * const RequestStatusFailed = @"RequestStatusFailed"; @interface DownLoadViewController ()<UITableViewDataSource,UITableViewDelegate,NSURLSessionDelegate,NSURLSessionTaskDelegate,NSURLSessionDownloadDelegate,NSURLSessionDataDelegate> { UITableView *mainTable; NSMutableArray *tableData; /** 保存所有下载信息的数组 */ NSMutableArray *downloadingArray; } @end @implementation DownLoadViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.view.backgroundColor = [UIColor whiteColor]; self.title = @"视频下载"; mainTable = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; mainTable.delegate = self; mainTable.dataSource = self; [self.view addSubview:mainTable]; tableData = [NSMutableArray array]; downloadingArray = [NSMutableArray array]; /** 请求下载列表 */ [self requestData]; } /** * 请求数据 */ - (void)requestData { AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; manager.requestSerializer = [AFJSONRequestSerializer serializer]; manager.responseSerializer = [AFJSONResponseSerializer serializer]; manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/plain", @"text/html", nil]; [manager GET:@"http://ac.ybjk.com/vod_v1.php?km=km3&m=sp" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { NSMutableDictionary *resultDic = (NSMutableDictionary *)responseObject; NSArray *array = resultDic[@"data"]; for (NSDictionary *dic in array) { DownModel *model = [[DownModel alloc] init]; model.name = dic[@"title"]; model.url = dic[@"url"]; [tableData addObject:model]; } /** 保存所有下载任务信息数组 初始化*/ for (int i = 0 ; i < tableData.count ; i++) { NSMutableDictionary *tmpDic = [NSMutableDictionary dictionary]; [downloadingArray addObject:tmpDic]; } NSLog(@"所有下载任务信息 长度 %lu",(unsigned long)downloadingArray.count); [mainTable reloadData]; } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"请求失败"); }]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return tableData.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString *cellId = [NSString stringWithFormat:@"%ld%ld",(long)indexPath.section,(long)indexPath.row]; BaseCell *cell = (BaseCell *)[tableView dequeueReusableCellWithIdentifier:cellId]; if (!cell) { cell = [[BaseCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId]; cell.selectionStyle = UITableViewCellSelectionStyleNone; } DownModel *model = [tableData objectAtIndex:indexPath.row]; cell.nameLabel.text = model.name; cell.downBtn.tag = indexPath.row; [cell.downBtn addTarget:self action:@selector(downBtnAction:) forControlEvents:UIControlEventTouchUpInside]; NSString *fileName = [NSString stringWithFormat:@"%@.mp4",model.name]; // 2. 生成沙盒的路径 NSArray *docs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *path = [docs[0] stringByAppendingPathComponent:fileName]; if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { /** 如果文件存在 */ cell.downBtn.hidden = YES; cell.sizeLabel.text = @"已下载至本地"; } return cell; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 60.0f; } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return 15.0f; } - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { return 0.1f; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; } /** * 刷新选中cell * * @param cell cell * @param indexPath 选中行数 */ - (void)updateCell:(BaseCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { NSMutableDictionary *downloadInfoDict = [downloadingArray objectAtIndex:indexPath.row]; /** 文件名称 */ NSString *fileName = [downloadInfoDict objectForKey:kMZDownloadKeyFileName]; cell.nameLabel.text = fileName; /** 文件大小 */ [cell.detailTextLabel setText:[downloadInfoDict objectForKey:kMZDownloadKeyDetails]]; /** 下载进度 */ [cell.progressView setProgress:[[downloadInfoDict objectForKey:kMZDownloadKeyProgress] floatValue]]; } #pragma mark - 下载事件 - (void)downBtnAction:(UIButton *)btn { /** 获得当前操作行数 */ NSIndexPath *path = [NSIndexPath indexPathForRow:btn.tag inSection:0]; BaseCell *cell = (BaseCell *)[mainTable cellForRowAtIndexPath:path]; /** 获得当前操作行数对象 */ DownModel *model = [tableData objectAtIndex:btn.tag]; /** 下载的文件名称 */ NSString *fileName = model.name; /** 下载的url */ NSString *fileURL = model.url; if (!btn.selected) { NSLog(@"开始下载"); [btn setSelected:YES]; /** 获得当前操作行数 下载任务信息 */ NSMutableDictionary *downloadInfo = [downloadingArray objectAtIndex:path.row]; /** 获得当前操作行数 下载任务 */ NSURLSessionDownloadTask *downloadTask = [downloadInfo objectForKey:kMZDownloadKeyTask]; if (downloadTask) { /** 执行断点下载 */ NSData *resumeData = [[downloadInfo objectForKey:kMZDownloadKeyResumeData] dataUsingEncoding:NSUTF8StringEncoding]; downloadTask = [self.sessionManager downloadTaskWithResumeData:resumeData]; [downloadTask resume]; } else { /** 添加下载任务 */ [self addDownloadTask:fileName fileURL:fileURL indexRow:btn.tag]; } } else { NSLog(@"暂停下载"); [btn setSelected:NO]; /** 获得当前操作行数 下载任务信息 */ NSMutableDictionary *downloadInfo = [downloadingArray objectAtIndex:path.row]; /** 获得当前操作行数 下载任务 */ NSURLSessionDownloadTask *downloadTask = [downloadInfo objectForKey:kMZDownloadKeyTask]; /** 获得当前操作行数 下载状态 */ NSString *downloadStatus = [downloadInfo objectForKey:kMZDownloadKeyStatus]; if ([downloadStatus isEqualToString:RequestStatusDownloading]) { /** 当前状态为正在下载,则暂停下载 */ // [downloadTask suspend]; /** 暂停下载 */ // [downloadTask cancel]; /** 断点下载,保存断点data */ [downloadTask cancelByProducingResumeData:^(NSData *resumeData) { NSString *dataString = [[NSString alloc] initWithData:resumeData encoding:NSUTF8StringEncoding]; NSLog(@"断点数据 %@",dataString); [downloadInfo setObject:dataString forKey:kMZDownloadKeyResumeData]; }]; [downloadInfo setObject:RequestStatusPaused forKey:kMZDownloadKeyStatus]; /** 设置下载任务信息为暂停状态 */ /** 更新下载任务数组中 当前任务信息 */ [downloadingArray replaceObjectAtIndex:path.row withObject:downloadInfo]; /** 刷新 当前 选中 cell */ [self updateCell:cell forRowAtIndexPath:path]; } } } #pragma mark - 懒加载 获得session - (NSURLSession *)sessionManager { static NSURLSession *session = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil]; }); return session; } /** * 添加下载任务 * * @param fileName 文件名 * @param fileURL 文件URL */ - (void)addDownloadTask:(NSString *)fileName fileURL:(NSString *)fileURL indexRow:(NSInteger)indexRow { /** 初始化下载任务 */ NSURL *url = [NSURL URLWithString:fileURL]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; NSURLSessionDownloadTask *downloadTask = [self.sessionManager downloadTaskWithRequest:request]; /** 启动下载任务 */ [downloadTask resume]; /** 保存本次下载任务信息 */ NSMutableDictionary *downloadInfo = [NSMutableDictionary dictionary]; [downloadInfo setObject:fileURL forKey:kMZDownloadKeyURL]; /** 下载url */ [downloadInfo setObject:fileName forKey:kMZDownloadKeyFileName]; /** 下载文件名称 */ /** 将保存任务信息的字典转化为json字符串,设置本次下载任务的描述 */ NSError *error = nil; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:downloadInfo options:NSJSONWritingPrettyPrinted error:&error]; NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; downloadTask.taskDescription = jsonString; /** 继续向字典中添加本次下载任务信息 */ [downloadInfo setObject:RequestStatusDownloading forKey:kMZDownloadKeyStatus]; /** 下载状态 (正在下载,暂停下载,下载失败) */ [downloadInfo setObject:downloadTask forKey:kMZDownloadKeyTask]; /** 本次下载任务 */ /** 将本次下载任务信息保存到数组中 */ // [downloadingArray addObject:downloadInfo]; [downloadingArray replaceObjectAtIndex:indexRow withObject:downloadInfo]; } #pragma mark - NSURLSession Delegate - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { /** 遍历下载任务信息数组,获得每一个下载任务信息 */ for (NSMutableDictionary *downloadDict in downloadingArray) { /** 获得当前所有下载任务中 与 代理方法中的 downloadTask 一致的 */ if ([downloadTask isEqual:[downloadDict objectForKey:kMZDownloadKeyTask]]) { dispatch_async(dispatch_get_main_queue(), ^{ /** 回到主线程,渲染UI */ float progress = (double)downloadTask.countOfBytesReceived/(double)downloadTask.countOfBytesExpectedToReceive; /** 获取当前任务所在cell */ NSInteger indexOfDownloadDict = [downloadingArray indexOfObject:downloadDict]; NSIndexPath *indexPathToRefresh = [NSIndexPath indexPathForRow:indexOfDownloadDict inSection:0]; BaseCell *cell = (BaseCell *)[mainTable cellForRowAtIndexPath:indexPathToRefresh]; /** 进度条 */ cell.progressView.progress = progress; /** 文件大小 */ cell.sizeLabel.text = [NSString stringWithFormat:@"%.2fM/%.2fM",(CGFloat)totalBytesWritten/1024/1024,(CGFloat)totalBytesExpectedToWrite/1024/1024]; /** 保存当前下载任务的进度 以及 文件大小信息 */ [downloadDict setObject:[NSString stringWithFormat:@"%f",progress] forKey:kMZDownloadKeyProgress]; /** 保存进度 */ [downloadDict setObject:cell.sizeLabel.text forKey:kMZDownloadKeyDetails]; /** 文件大小 */ }); break; } } } - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { /** 遍历下载任务信息数组,获得每一个下载任务信息 */ for (NSMutableDictionary *downloadDict in downloadingArray) { /** 获得当前所有下载任务中 与 代理方法中的 downloadTask 一致的 */ if ([downloadTask isEqual:[downloadDict objectForKey:kMZDownloadKeyTask]]) { /** 保存的文件名 */ NSString *fileName = [downloadDict objectForKey:kMZDownloadKeyFileName]; /** 保存路径 */ NSString *savePath = [fileDest stringByAppendingPathComponent:fileName]; NSURL *fileURL = [NSURL fileURLWithPath:savePath]; NSLog(@"下载文件保存路径: %@",savePath); /** 将下载好的文件从临时文件夹中保存到指定路径 */ if (location) { NSError *error = nil; [[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error]; if (error) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:error.localizedDescription delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; [alert show]; } } break; } } } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { NSLog(@"error %@",error.localizedDescription); NSLog(@"===== %@",[error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData]); } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. }
Are you trying to make somethings similar to IDM (Internet download manager) ?
I did not understand what your requirements are?
hey,I refer your idea to write a download manager, but does not support breakpoints download, hope you can help me analyze, be grateful.
code: