iOS開發之NSURLSessionDataTask實現大檔案離線斷點下載(重點),

來源:互聯網
上載者:User

iOS開發之NSURLSessionDataTask實現大檔案離線斷點下載(重點),

iOS開發之NSURLSessionDataTask實現大檔案離線斷點下載(重點)。源碼下載:https://github.com/coderZYGui/ZYBreakpointDownload

如下:

知識點:

1.擷取指定檔案路徑對應的檔案大小(已經下載過的檔案資料大小 )

2.( 斷點下載思路 )使用NSMutableURLRequest 建立可變請求. 佈建要求頭資訊,告訴伺服器請求的是哪一部分資料(請求當前下載過的資料( 知識點1,中已經下載過的檔案資料大小) 後的資料 )

 

    // 只要設定HTTP要求標頭的Range屬性, 就可以實現從指定位置開始下載     表示頭500個位元組:Range: bytes=0-499     表示第二個500位元組:Range: bytes=500-999     表示最後500個位元組:Range: bytes=-500     表示500位元組以後的範圍:Range: bytes=500-
3.使用response.expectedContentLength 獲得本次請求的檔案資料總大小.

 

注意:

本次請求的檔案資料大小 !=檔案總大小(第一次發送請求時,response.expectedContentLength 為檔案的大小, 如果再次發送請求的時候,此時的self.totalSize就小於檔案的大小,因此在後面計算 1.0 * self.currentSize / self.totalSize的時候,會出現資料錯亂)因此要加上當前已經下載的資料.

4. 在接收到伺服器響應的代理方法中. 預設是取消該請求.設定枚舉為NSURLSessionResponseAllow 接收

completionHandler(NSURLSessionResponseAllow);

 

5.判斷下載資料 self.currentSize == 0建立空檔案.防止多次發送請求時建立多個空檔案,導致檔案資料大小紊亂.

 

6.使用檔案控制代碼在每次下載過的資料後,繼續拼接. [ self.handle seekToEndofFile ];

 

7. 將檔案的總資料 和已經下載的檔案資料 都儲存到沙箱中, 當程式運行時將已經下載的資料 / 檔案總資料 設定到 slider的value上.

 

8. 釋放 NSURLSession 對象

 

- (void)dealloc{    // 如果session設定代理的話,會有一個強引用.不會被釋放.因此最後要釋放session對象:調用下面兩個方法都行.\    否則會有記憶體流失.    // finishTasksAndInvalidate    [self.session invalidateAndCancel];}

 

代碼:

 

//  Created by 朝陽 on 2017/12/19.//  Copyright © 2017年 sunny. All rights reserved.//#import "ViewController.h"#define FileName @"zy.mp4"@interface ViewController ()@property (nonatomic, strong) NSFileHandle *handle;@property (nonatomic, assign) NSInteger totalSize;@property (nonatomic, assign) NSInteger currentSize;@property (nonatomic, strong) NSString *fullPath;@property (weak, nonatomic) IBOutlet UISlider *slider;@property (nonatomic,strong) NSURLSessionDataTask *dataTask;@property (nonatomic,strong) NSURLSession *session;@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad];        //設定slider的進度狀態 = 1.0 * 已經下載的檔案大小 / 總檔案大小    self.slider.value = [self getSandboxFileSize];        if (self.slider.value == 1.0) {        self.slider.value = 0;    }    }- (CGFloat)getSandboxFileSize{    //1. 讀取沙箱中儲存的總檔案大小    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];    NSNumber *totalFileSize = [defaults objectForKey:@"fileSize"];    NSNumber *currentFileSize = [defaults objectForKey:@"currentFileSize"];        NSInteger totalSize = [totalFileSize integerValue];    NSInteger currentSize = [currentFileSize integerValue];        NSLog(@"%ld",totalSize);    NSLog(@"%ld",currentSize);        return 1.0 * currentSize / totalSize;}#pragma -mark lazy loading- (NSURLSession *)session{    if (!_session) {        //建立會話對象,並設定代理        _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];    }    return _session;}- (NSString *)fullPath{    if (!_fullPath) {                //2. 擷取檔案全路徑        _fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingString:FileName];    }    return _fullPath;}- (NSURLSessionDataTask *)dataTask{    if (!_dataTask) {        //1. url        NSURL *url = [NSURL URLWithString:@"https://flv2.bn.netease.com/videolib3/1604/28/fVobI0704/SD/fVobI0704-mobile.mp4"];                //2. 建立請求對象        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];        // 擷取指定檔案路徑對應的檔案大小(當前已經下載的檔案大小)        self.currentSize = [self getFileSize];        NSLog(@"currentSize----+++++++++++++++++++----%ld",self.currentSize);        //2.1 佈建要求頭資訊,告訴伺服器請求的哪一部分資料(請求當前下載過的資料 之後的資料)        // 只要設定HTTP要求標頭的Range屬性, 就可以實現從指定位置開始下載        /*         表示頭500個位元組:Range: bytes=0-499         表示第二個500位元組:Range: bytes=500-999         表示最後500個位元組:Range: bytes=-500         表示500位元組以後的範圍:Range: bytes=500-         */        NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];        [request setValue:range forHTTPHeaderField:@"Range"];                //3. 建立Task任務        _dataTask = [self.session dataTaskWithRequest:request];    }    return _dataTask;}// 擷取指定檔案路徑對應的檔案大小- (NSInteger)getFileSize{    NSDictionary *fileInfoDict = [[NSFileManager defaultManager] attributesOfItemAtPath:self.fullPath error:nil];    NSLog(@"%@",fileInfoDict);    // 獲得字典中檔案的資訊-檔案大小    // currentSize = self.currentSize;    NSInteger currentSize = [fileInfoDict[@"NSFileSize"] integerValue];        return currentSize;}- (IBAction)startDwonload:(id)sender{    NSLog(@"+++++++++++++++開始下載");    //5. 執行Task    [self.dataTask resume];}- (IBAction)supendDownload:(id)sender{    NSLog(@"+++++++++++++++暫停下載");    [self.dataTask suspend];}// cancel方法: 不可恢複下載- (IBAction)cancelDownload:(id)sender{    NSLog(@"+++++++++++++++取消下載");    [self.dataTask cancel];    // 清空dataTask.在resumeDownload:方法中,self.dataTask 走懶載入方法    self.dataTask = nil;}// 恢複下載- (IBAction)resumeDownload:(id)sender{    NSLog(@"+++++++++++++++恢複下載");    [self.dataTask resume];}#pragma -mark NSURLSessionDataDelegate/** 接收到伺服器的響應 它預設會取消該請求  @param session 會話對象 @param dataTask 請求任務 @param response 回應標頭資訊 @param completionHandler 回調 傳給系統 */- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{        //0. 得到 檔案的總大小(本次請求的檔案資料的總大小)    // 本次請求的檔案資料大小 != 檔案總大小(如果再次發送請求的時候,此時的self.totalSize 就小於檔案的大小,因此在\    在後面計算 1.0 * self.currentSize / self.totalSize 的時候,會出現資料錯亂) 因此要加上當前已經下載的資料.    self.totalSize = response.expectedContentLength + self.currentSize;        // 將檔案總大小寫入到沙箱中    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];    [defaults setObject:@(self.totalSize) forKey:@"fileSize"];        /*     NSURLSessionResponseCancel = 0,取消 預設     NSURLSessionResponseAllow = 1, 接收     NSURLSessionResponseBecomeDownload = 2, 變成下載任務     NSURLSessionResponseBecomeStream        變成流     */        //1. 因為系統預設是 取消工作要求. 所以要設定 枚舉 為接收    completionHandler(NSURLSessionResponseAllow);            // 如果當前下載的資料為0. 就建立一個空檔案(防止,多建立空檔案導致檔案大小紊亂)    if (self.currentSize == 0) {        //3. 建立一個空檔案(將檔案寫入到沙箱中)        [[NSFileManager defaultManager] createFileAtPath:self.fullPath contents:nil attributes:nil];    }    //4. 建立檔案控制代碼    self.handle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath];    //5. 每次在下載過資料後,繼續拼接    [self.handle seekToEndOfFile];}/** 接收到伺服器返回的資料  調用多次  @param session 會話對象 @param dataTask 請求任務 @param data 本次下載的資料 */-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{    //1. 寫入資料到檔案    [self.handle writeData:data];    //2. 拼接已經下載過的資料    self.currentSize += data.length;    // 將已經下載的檔案大小寫入到沙箱中    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];    [defaults setObject:@(self.currentSize) forKey:@"currentFileSize"];        //3. 下載進度    NSLog(@"%f",1.0 * self.currentSize / self.totalSize);        self.slider.value = 1.0 * self.currentSize / self.totalSize;}/** 請求結束或失敗的時候調用  @param session 會話對象 @param task 請求任務 @param error 錯誤資訊 */- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{    //1. 關閉檔案控制代碼    [self.handle closeFile];    self.handle = nil;        NSLog(@"%@",self.fullPath);    }- (void)dealloc{    // 如果session設定代理的話,會有一個強引用.不會被釋放.因此最後要釋放session對象:調用下面兩個方法都行.\    否則會有記憶體流失.    // finishTasksAndInvalidate    [self.session invalidateAndCancel];}@end

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.