Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not Resuming #15

Closed
mahong125 opened this issue Aug 31, 2015 · 1 comment
Closed

Not Resuming #15

mahong125 opened this issue Aug 31, 2015 · 1 comment

Comments

@mahong125
Copy link

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.
}
@mzeeshanid
Copy link
Owner

Are you trying to make somethings similar to IDM (Internet download manager) ?

I did not understand what your requirements are?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants