美文网首页收藏iosiOS way, life wayiOS技术专题
OC网络:NSURLSessionDataTask实现离线断点下

OC网络:NSURLSessionDataTask实现离线断点下

作者: cyh老崔 | 来源:发表于2015-12-10 16:02 被阅读611次

    NSURLSessionDataDelegate代理方法实现离线断点下载,即程序意外退出时,再登陆,可以根据上次的进度继续下载.

    原理:

    • 边下载边写入到caches
    • 每次开启下载时,设置请求头的信息:下载的位置.
    
    #define KfileName @"123.mp4"
    
    @interface ViewController ()<NSURLSessionDataDelegate>
    @property (weak, nonatomic) IBOutlet UILabel *label;
    
    @property (weak, nonatomic) IBOutlet UIProgressView *progress;
    /** currentsize */
    @property (nonatomic, assign) NSInteger currentSize;
    @property (nonatomic, assign) NSInteger totalSize;
    /** dataTask */
    @property (nonatomic, strong) NSURLSessionDataTask *dataTask;
    /** outPutStream */
    @property (nonatomic, strong) NSOutputStream *outPutStream;
    
    @end
    
    @implementation ViewController
    
    #pragma mark -------------------------------
    #pragma mark Events
    - (IBAction)startBtnClick:(id)sender {
        
        NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
        
        //确定是否存在已经下载的文件,如存在,继续下载.
        self.currentSize = [self getSize];
        
        //new dataTask
        NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_02.mp4"];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
        
        //设置请求头信息
        NSString *header = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];
        [request setValue:header forHTTPHeaderField:@"Range"];
        
        NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
        self.dataTask = dataTask;
        
        [self.dataTask resume];
    }
    - (IBAction)suspendBtnClick:(id)sender {
        [self.dataTask suspend];
    }
    
    
    - (IBAction)continueBtnClick:(id)sender {
        [self.dataTask resume];
    }
    
    #pragma mark -------------------------------
    #pragma mark methods
    - (NSInteger)getSize{
        //0.拼接文件全路径
        NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:KfileName];
        
        //先把沙盒中的文件大小取出来
        NSDictionary *dict = [[NSFileManager defaultManager]attributesOfItemAtPath:fullPath error:nil];
        NSInteger size = [[dict objectForKey:@"NSFileSize"]integerValue];
        return size;
    }
    
    #pragma mark -------------------------------
    #pragma mark NSURLSessionDataDelegate
    
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{
        
        //此处注意,不设置为allow,其它delegate methods将不被执行
        completionHandler(NSURLSessionResponseAllow);
        
        self.totalSize = response.expectedContentLength + self.currentSize;
        
        //0.拼接文件全路径
        
        NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:KfileName];
        
        //1.创建输出流
        NSOutputStream *outPutStream = [NSOutputStream outputStreamToFileAtPath:fullPath append:YES];
        [outPutStream open];
        self.outPutStream = outPutStream;
    }
    
    //2.当接受到服务器返回的数据的时候调用,会调用多次
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
        
        self.currentSize += data.length;
        CGFloat rate = 1.0 * self.currentSize / self.totalSize;
        self.progress.progress = rate;
        self.label.text = [NSString stringWithFormat:@"%.2f", rate];
        [self.outPutStream write:data.bytes maxLength:data.length];
        
    }
    
    //3.当整个请求结束的时候调用,error有值的话,那么说明请求失败
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
        
        [self.outPutStream close];
        self.outPutStream = nil;
    }
    
    @end
    
    

    细节未完全处理:btn的enable状态,方法抽取等.

    相关文章

      网友评论

      • 黑幕居士:不知为什么,请求到的文件总长度 (response.expectedContentLength) 只有几字节,瞬间就100%,文件也没下完
        黑幕居士:@老司机Wicky 是的,我抄完你的代码后, 把=改成空格, 就能完整下载
        老司机Wicky:@黑幕居士 你是说把range里面的=去掉么
        黑幕居士:@黑幕居士 终于找到原因了,把 @"bytes=%zd-" 改成 @"bytes %zd-"就能正常下载了
      • 257f312dccb8: 你好 有完整的例子 能发一份学习学习吗? wb911025@163.com 谢谢

      本文标题:OC网络:NSURLSessionDataTask实现离线断点下

      本文链接:https://www.haomeiwen.com/subject/tllyhttx.html