多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > 使用NSURLSession和NSURLSessionDataTask實現斷點續傳

使用NSURLSession和NSURLSessionDataTask實現斷點續傳

來源:程序員人生   發布時間:2016-03-24 09:11:50 閱讀次數:3144次


蘋果提供的NSURLSessionDownloadTask雖然能實現斷點續傳,但是有些情況是沒法處理的,比如程序強迫退出或沒有調用

cancelByProducingResumeData取消方法,這時候就沒法斷點續傳了。


使用NSURLSession和NSURLSessionDataTask實現斷點續傳的進程是:

1、配置NSMutableURLRequest對象的Range要求頭字段信息

2、創建使用代理的NSURLSession對象

3、使用NSURLSession對象和NSMutableURLRequest對象創建NSURLSessionDataTask對象,啟動任務。

4、在NSURLSessionDataDelegate的didReceiveData方法中追加獲得下載數據到目標文件


下面是具體實現,封裝了1個續傳管理器。可以直接拷貝到你的工程里,也能夠參考我提供的DEMO:http://pan.baidu.com/s/1c0BHToW


//

//  MQLResumeManager.h

//

//  Created by MQL on 15/10/21.

//  Copyright ? 2015. All rights reserved.

//


#import


@interface MQLResumeManager : NSObject


/**

 *  創建斷點續傳管理對象,啟動下載要求

 *

 *  @param url          文件資源地址

 *  @param targetPath   文件寄存路徑

 *  @param success      文件下載成功的回調塊

 *  @param failure      文件下載失敗的回調塊

 *  @param progress     文件下載進度的回調塊

 *

 *  @return 斷點續傳管理對象

 *

 */

+(MQLResumeManager*)resumeManagerWithURL:(NSURL*)url

                                targetPath:(NSString*)targetPath

                                success:(void (^)())success

                                failure:(void (^)(NSError *error))failure

                               progress:(void (^)(longlong totalReceivedContentLength, long long totalContentLength))progress;


/**

 *  啟動斷點續傳下載要求

 */

-(void)start;


/**

 *  取消斷點續傳下載要求

 */

-(void)cancel;



@end



//

//  MQLResumeManager.m

//

//  Created by MQL on 15/10/21.

//  Copyright ? 2015. All rights reserved.

//


#import "MQLResumeManager.h"


typedef void (^completionBlock)();

typedef void (^progressBlock)();


@interface MQLResumeManager ()<NSURLSessionDelegate,NSURLSessionTaskDelegate>


@property (nonatomic,strong) NSURLSession *session;   //注意1個session只能有1個要求任務

@property(nonatomic,readwrite, retain)NSError *error;//要求出錯

@property(nonatomic,readwrite, copy)completionBlock completionBlock;

@property(nonatomic,readwrite, copy)progressBlock progressBlock;


@property (nonatomic,strong) NSURL *url;          //文件資源地址

@property (nonatomic,strong) NSString *targetPath;//文件寄存路徑

@property longlong totalContentLength;             //文件總大小

@property longlong totalReceivedContentLength;     //已下載大小


/**

 *  設置成功、失敗回調block

 *

 *  @param success 成功回調block

 *  @param failure 失敗回調block

 */

- (void)setCompletionBlockWithSuccess:(void (^)())success

                              failure:(void (^)(NSError *error))failure;


/**

 *  設置進度回調block

 *

 *  @param progress

 */

-(void)setProgressBlockWithProgress:(void (^)(longlong totalReceivedContentLength, long long totalContentLength))progress;


/**

 *  獲得文件大小

 *  @param path 文件路徑

 *  @return 文件大小

 *

 */

- (long long)fileSizeForPath:(NSString *)path;


@end


@implementation MQLResumeManager


/**

 *  設置成功、失敗回調block

 *

 *  @param success 成功回調block

 *  @param failure 失敗回調block

 */

- (void)setCompletionBlockWithSuccess:(void (^)())success

                              failure:(void (^)(NSError *error))failure{


    __weak typeof(self) weakSelf =self;

    self.completionBlock = ^ {


        dispatch_async(dispatch_get_main_queue(), ^{


            if (weakSelf.error) {

                if (failure) {

                    failure(weakSelf.error);

                }

            } else {

                if (success) {

                    success();

                }

            }


        });

    };

}


/**

 *  設置進度回調block

 *

 *  @param progress

 */

-(void)setProgressBlockWithProgress:(void (^)(longlong totalReceivedContentLength, long long totalContentLength))progress{


    __weak typeof(self) weakSelf =self;

    self.progressBlock = ^{


        dispatch_async(dispatch_get_main_queue(), ^{


            progress(weakSelf.totalReceivedContentLength, weakSelf.totalContentLength);

        });

    };

}


/**

 *  獲得文件大小

 *  @param path 文件路徑

 *  @return 文件大小

 *

 */

- (long long)fileSizeForPath:(NSString *)path {


    long long fileSize =0;

    NSFileManager *fileManager = [NSFileManagernew]; // not thread safe

    if ([fileManager fileExistsAtPath:path]) {

        NSError *error = nil;

        NSDictionary *fileDict = [fileManager attributesOfItemAtPath:path error:&error];

        if (!error && fileDict) {

            fileSize = [fileDict fileSize];

        }

    }

    return fileSize;

}


/**

 *  創建斷點續傳管理對象,啟動下載要求

 *

 *  @param url          文件資源地址

 *  @param targetPath   文件寄存路徑

 *  @param success      文件下載成功的回調塊

 *  @param failure      文件下載失敗的回調塊

 *  @param progress     文件下載進度的回調塊

 *

 *  @return 斷點續傳管理對象

 *

 */

+(MQLResumeManager*)resumeManagerWithURL:(NSURL*)url

                              targetPath:(NSString*)targetPath

                                 success:(void (^)())success

                                 failure:(void (^)(NSError *error))failure

                                progress:(void (^)(longlong totalReceivedContentLength, long long totalContentLength))progress{


    MQLResumeManager *manager = [[MQLResumeManageralloc]init];


    manager.url = url;

    manager.targetPath = targetPath;

    [manager setCompletionBlockWithSuccess:successfailure:failure];

    [manager setProgressBlockWithProgress:progress];


    manager.totalContentLength =0;

    manager.totalReceivedContentLength =0;


    return manager;

}


/**

 *  啟動斷點續傳下載要求

 */

-(void)start{


    NSMutableURLRequest *request = [[NSMutableURLRequestalloc]initWithURL:self.url];


    longlong downloadedBytes =self.totalReceivedContentLength = [selffileSizeForPath:self.targetPath];

    if (downloadedBytes > 0) {


        NSString *requestRange = [NSStringstringWithFormat:@"bytes=%llu-", downloadedBytes];

        [request setValue:requestRange forHTTPHeaderField:@"Range"];

    }else{


        int fileDescriptor = open([self.targetPathUTF8String], O_CREAT |O_EXCL | O_RDWR,0666);

        if (fileDescriptor > 0) {

            close(fileDescriptor);

        }

    }


    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfigurationdefaultSessionConfiguration];

    NSOperationQueue *queue = [[NSOperationQueuealloc]init];

    self.session = [NSURLSessionsessionWithConfiguration:sessionConfiguration delegate:selfdelegateQueue:queue];


    NSURLSessionDataTask *dataTask = [self.sessiondataTaskWithRequest:request];

    [dataTask resume];

}


/**

 *  取消斷點續傳下載要求

 */

-(void)cancel{


    if (self.session) {


        [self.sessioninvalidateAndCancel];

        self.session =nil;

    }

}


#pragma mark -- NSURLSessionDelegate

/* The last message a session delegate receives.  A session will only become

 * invalid because of a systemic error or when it has been

 * explicitly invalidated, in which case the error parameter will be nil.

 */

- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullableNSError *)error{


    NSLog(@"didBecomeInvalidWithError");

}


#pragma mark -- NSURLSessionTaskDelegate

/* Sent as the last message related to a specific task.  Error may be

 * nil, which implies that no error occurred and this task is complete.

 */

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task

didCompleteWithError:(nullable NSError *)error{


    NSLog(@"didCompleteWithError");


    if (error == nil &&self.error ==nil) {


        self.completionBlock();


    }else if (error !=nil){


        if (error.code != -999) {


            self.error = error;

            self.completionBlock();

        }


    }else if (self.error !=nil){


        self.completionBlock();

    }



}


#pragma mark -- NSURLSessionDataDelegate

/* Sent when data is available for the delegate to consume.  It is

 * assumed that the delegate will retain and not copy the data.  As

 * the data may be discontiguous, you should use

 * [NSData enumerateByteRangesUsingBlock:] to access it.

 */

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask

    didReceiveData:(NSData *)data{


    //根據status code的不同,做相應的處理

    NSHTTPURLResponse *response = (NSHTTPURLResponse*)dataTask.response;

    if (response.statusCode ==200) {


        self.totalContentLength = dataTask.countOfBytesExpectedToReceive;


    }else if (response.statusCode ==206){


        NSString *contentRange = [response.allHeaderFieldsvalueForKey:@"Content-Range"];

        if ([contentRange hasPrefix:@"bytes"]) {

            NSArray *bytes = [contentRangecomponentsSeparatedByCharactersInSet:[NSCharacterSetcharacterSetWithCharactersInString:@" -/"]];

            if ([bytes count] == 4) {

                self.totalContentLength = [[bytesobjectAtIndex:3]longLongValue];

            }

        }

    }else if (response.statusCode ==416){


        NSString *contentRange = [response.allHeaderFieldsvalueForKey:@"Content-Range"];

        if ([contentRange hasPrefix:@"bytes"]) {

            NSArray *bytes = [contentRangecomponentsSeparatedByCharactersInSet:[NSCharacterSetcharacterSetWithCharactersInString:@" -/"]];

            if ([bytes count] == 3) {


                self.totalContentLength = [[bytesobjectAtIndex:2]longLongValue];

                if (self.totalReceivedContentLength ==self.totalContentLength) {


                    //說明已下完


                    //更新進度

                    self.progressBlock();

                }else{


                    //416 Requested Range Not Satisfiable

                    self.error = [[NSErroralloc]initWithDomain:[self.urlabsoluteString] code:416userInfo:response.allHeaderFields];

                }

            }

        }

        return;

    }else{


        //其他情況還沒發現

        return;

    }


    //向文件追加數據

    NSFileHandle *fileHandle = [NSFileHandlefileHandleForUpdatingAtPath:self.targetPath];

    [fileHandle seekToEndOfFile]; //將節點跳到文件的末尾


    [fileHandle writeData:data];//追加寫入數據

    [fileHandle closeFile];


    //更新進度

    self.totalReceivedContentLength += data.length;

    self.progressBlock();

}



@end

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 亚洲成a人片在线播放观看国产 | 91情国产l精品国产亚洲区 | 国产亚洲精品精品国产亚洲综合 | 国产高清精品入口91 | 免费在线观看h | 性做久久久久久久 | 在线视频午夜 | 亚洲乱码在线观看 | 精品一区二区三区自拍图片区 | 国产日韩网站 | 最近最新免费中文字幕高清 | 成年视频国产免费观看 | 午夜在线视频观看 | 2022精品福利在线小视频 | 波多野结衣178部中文字幕 | 欧美自拍网站 | 尤物视频免费观看 | 欧美成人免费一区在线播放 | 日韩欧美视频一区 | 精品国产不卡一区二区三区 | 福利精品一区 | 亚洲黄色在线视频 | 中国美女隐私无遮挡免费视频 | 日本一本高清v免费视频 | 精品国产综合区久久久久久 | 成人a视频| 一本到亚洲网 | 亚洲欧美视频 | 国内精品久久久久影院网站 | 亚洲欧美久久婷婷爱综合一区天堂 | 欧美午夜精品久久久久免费视 | 另类专区另类专区亚洲 | 精品日韩欧美一区二区三区在线播放 | 国产69精品久久久久99 | 操操网址 | 乱码亚洲一区二区三区 | 羞羞视频免费入口网站 | h网站免费观看 | 亚洲综合资源 | 抖音毛片 | 成在线人免费视频 |