前言
- DEPRECATED: The NSURLConnection class should no longer be used.
- NSURLSession is the replacement for NSURLConnection
- 從 iOS 9 開始 NSURLConnection 的大部分方法被廢棄。
一、NSURLConnection
二、NSURLConnection 同步 GET 請求
// 設置網絡接口
NSString *urlStr = @"http://192.168.88.200:8080/MJServer/video?type=JSON";
// 設置請求路徑
NSURL *url = [NSURL URLWithString:urlStr];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
// 建立同步網絡請求
NSData *syncNetData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:NULL error:NULL];
三、NSURLConnection 同步 POST 請求
// 設置網絡接口
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200:8080/MJServer/video"];
// 建立請求對象
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
// 設置請求方式,默認爲 GET 請求
urlRequest.HTTPMethod = @"POST";
// 設置請求體(請求參數)
urlRequest.HTTPBody = [@"type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
// 建立同步網絡請求
NSData *syncNetData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:NULL error:NULL];
四、NSURLConnection 異步 GET 請求
4.1 使用 block 回調方式
// 設置網絡接口
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200:8080/MJServer/video?type=XML"];
// 建立請求對象
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
// 建立異步網絡請求
[NSURLConnection sendAsynchronousRequest:urlRequest
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError == nil && data != nil) {
}
}];
4.2 使用 協議 方式
// 遵照協議 <NSURLConnectionDataDelegate>
@property(nonatomic, retain)NSMutableData *asyncNetData;
// 設置網絡接口
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200:8080/MJServer/video?type=XML"];
// 建立請求對象
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
// 建立異步網絡請求
[NSURLConnection connectionWithRequest:urlRequest delegate:self];
// 協議方法
// 接收到服務器的響應
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// 異步下載數據源初始化
self.asyncNetData = [[NSMutableData alloc] init];
}
// 接收到服務器數據
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// 拼接從服務器下載的數據
[self.asyncNetData appendData:data];
}
// 服務器的數據加載完畢
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// 處理從服務器下載的數據
self.textView.text = [[NSString alloc] initWithData:self.asyncNetData encoding:NSUTF8StringEncoding];
}
// 請求錯誤
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
}
五、NSURLConnection 異步 POST 請求
5.1 使用 block 回調方式
// 設置網絡接口
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200:8080/MJServer/video"];
// 建立請求對象
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
// 設置請求方式,默認爲 GET 請求
urlRequest.HTTPMethod = @"POST";
// 設置請求體(請求參數)
urlRequest.HTTPBody = [@"type=XML" dataUsingEncoding:NSUTF8StringEncoding];
// 建立異步網絡請求
[NSURLConnection sendAsynchronousRequest:urlRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError == nil && data != nil) {
}
}];
5.2 使用 協議 方式
// 遵照協議 <NSURLConnectionDataDelegate>
// 設置網絡接口
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200:8080/MJServer/video"];
// 建立請求對象
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
// 設置請求方式,默認爲 GET 請求
urlRequest.HTTPMethod = @"POST";
// 設置請求體(請求參數)
urlRequest.HTTPBody = [@"type=XML" dataUsingEncoding:NSUTF8StringEncoding];
// 建立異步網絡請求
[NSURLConnection connectionWithRequest:urlRequest delegate:self];
// 協議方法
// 已經發送請求體
- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
}
// 接收到服務器的響應
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
}
// 接收到服務器數據
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
}
// 服務器的數據加載完畢
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
}
// 請求錯誤
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
}
六、NSURLConnection 文件下載
6.1 獲取文件信息
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/download/file/minion_02.mp4"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 使用 HEAD 請求方式
request.HTTPMethod = @"HEAD";
NSURLResponse *response = nil;
NSError *error = nil;
// 使用同步請求方式,後續的下載會依賴於此
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error == nil && response != nil) {
// 獲取文件大小或名稱
NSLog(@"要下載文件的長度 %tu", response.expectedContentLength);
}
6.2 使用 GET 數據請求方式下載,文件句柄存儲
// 下載文件的總長度
@property (nonatomic, assign) long long expectedContentLength;
// 當前文件大小
@property (nonatomic, assign) long long recvedfileLength;
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/download/file/minion_02.mp4"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
// 遵照協議 <NSURLConnectionDataDelegate>
[NSURLConnection connectionWithRequest:urlRequest delegate:self];
// 協議方法
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"321.mp4"];
// 若是文件不存在,方法不會出錯
[[NSFileManager defaultManager] removeItemAtPath:documentsPath error:NULL];
// 獲取數據總大小
self.expectedContentLength = response.expectedContentLength;
self.recvedfileLength = 0;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// 將從服務器下載的數據直接寫入文件
[self writeToFile:data];
// 計算當前數據下載完成的大小
self.recvedfileLength += data.length;
// 計算下載進度
float progress = (float)self.recvedfileLength / self.expectedContentLength;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
}
// 將數據寫入文件
- (void)writeToFile:(NSData *)data {
/*
NSFileManager:文件管理器,文件複製,刪除,是否存在...操做,相似於在 Finder 中進行的操做
NSFileHandle :文件 "句柄(指針)" Handle 操縱桿,凡事看到 Handle 單詞,表示對前面一個名詞(File)的操做,
對一個文件進行獨立的操做。
*/
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"321.mp4"];
// 打開文件,若是文件不存在,fp == nil
NSFileHandle *fp = [NSFileHandle fileHandleForWritingAtPath:documentsPath];
// 若是文件不存在
if (fp == nil) {
// 將數據直接寫入文件
[data writeToFile:documentsPath atomically:YES];
} else {
// 將文件指針移動到文件末尾
[fp seekToEndOfFile];
// 寫入數據
[fp writeData:data];
// 關閉文件,C 語言中有一個默認的約定,凡事打開文件,都必須關閉
[fp closeFile];
}
}
6.3 使用 GET 數據請求方式下載,文件輸出流存儲
// 下載文件的總長度
@property (nonatomic, assign) long long expectedContentLength;
// 當前文件大小
@property (nonatomic, assign) long long recvedfileLength;
// 輸出數據流
@property (nonatomic, strong) NSOutputStream *fileStream;
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/download/file/minion_02.mp4"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
// 遵照協議 <NSURLConnectionDataDelegate>
[NSURLConnection connectionWithRequest:urlRequest delegate:self];
// 協議方法
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"312.mp4"];
// 若是文件不存在,方法不會出錯
[[NSFileManager defaultManager] removeItemAtPath:documentsPath error:NULL];
// 以拼接的方式實例化文件流
self.fileStream = [[NSOutputStream alloc] initToFileAtPath:documentsPath append:YES];
// 打開文件流
[self.fileStream open];
// 獲取數據總大小
self.expectedContentLength = response.expectedContentLength;
self.recvedfileLength = 0;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// 將數據的 "字節"一次性寫入文件流,而且指定數據長度
[self.fileStream write:data.bytes maxLength:data.length];
// 計算當前數據下載完成的大小
self.recvedfileLength += data.length;
// 計算下載進度
float progress = (float)self.recvedfileLength / self.expectedContentLength;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// 關閉文件流
[self.fileStream close];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// 關閉文件流
[self.fileStream close];
}
6.4 使用 專用下載 方式
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/download/file/minion_01.mp4"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
// 遵照協議 <NSURLConnectionDownloadDelegate>
[NSURLConnection connectionWithRequest:urlRequest delegate:self];
// 協議方法
- (void)connection:(NSURLConnection *)connection didWriteData:(long long)bytesWritten totalBytesWritten:(long long)totalBytesWritten expectedTotalBytes:(long long)expectedTotalBytes {
/*
下載進度:
bytesWritten 本次下載子節數
totalBytesWritten 已經下載字節數
expectedTotalBytes 總下載字節數(文件總大小)
*/
float progress = (float)totalBytesWritten / expectedTotalBytes;
NSLog(@"%f", progress);
}
- (void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *) destinationURL {
/*
destinationURL 下載保存的路徑,下載完成以後,找不到下載的文件。
*/
NSLog(@"%@", destinationURL);
}
6.5 斷點續傳下載
// 下載文件的總長度
@property (nonatomic, assign) long long expectedContentLength;
// 當前文件大小
@property (nonatomic, assign) long long recvedfileLength;
// 輸出數據流
@property (nonatomic, strong) NSOutputStream *fileStream;
// 目標目錄
@property (nonatomic, copy) NSString *targetPath;
@property (nonatomic, strong) NSURLConnection *conn;
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/download/file/minion_02.mp4"];
// 檢查服務器上的文件信息
[self checkServerFileInfoWithURL:url];
// 檢查本地文件信息
long long fileSize = [self checkLocalFileInfo];
// 文件已經下載到本地
if (fileSize == self.expectedContentLength) {
return;
}
// 根據本地文件的長度,從對應 "偏移" 位置開始下載
[self downloadWithURL:url offset:fileSize];
// 檢查服務器上的文件信息
- (void)checkServerFileInfoWithURL:(NSURL *)url {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"HEAD";
NSURLResponse *response = nil;
NSError *error = nil;
// 發送同步方法
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error == nil && response != nil) {
// 文件大小
self.expectedContentLength = response.expectedContentLength;
// 文件名,保存到臨時文件夾
self.targetPath = [NSTemporaryDirectory() stringByAppendingPathComponent:response.suggestedFilename];
}
}
// 檢查本地文件信息
- (long long)checkLocalFileInfo {
long long fileSize = 0;
// 檢查本地是否存在文件
if ([[NSFileManager defaultManager] fileExistsAtPath:self.targetPath]) {
NSDictionary *dict = [[NSFileManager defaultManager] attributesOfItemAtPath:self.targetPath error:NULL];
// 獲取文件大小
fileSize = [dict fileSize];
}
// 判斷是否比服務器的文件大
if (fileSize > self.expectedContentLength) {
// 刪除文件
[[NSFileManager defaultManager] removeItemAtPath:self.targetPath error:NULL];
fileSize = 0;
}
return fileSize;
}
// 從斷點處開始下載
- (void)downloadWithURL:(NSURL *)url offset:(long long)offset {
// 記錄本地文件大小
self.recvedfileLength = offset;
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:1 timeoutInterval:15];
// 一旦設置了 Range,response 的狀態碼會變成 206
[urlRequest setValue:[NSString stringWithFormat:@"bytes=%lld-", offset] forHTTPHeaderField:@"Range"];
// 遵照協議 <NSURLConnectionDataDelegate>
self.conn = [NSURLConnection connectionWithRequest:urlRequest delegate:self];
[self.conn start];
}
// 暫停下載
- (void)pause1 {
[self.conn cancel];
}
// 協議方法
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// 以拼接的方式實例化文件流
self.fileStream = [[NSOutputStream alloc] initToFileAtPath:self.targetPath append:YES];
[self.fileStream open];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// 將數據的 "字節"一次性寫入文件流,而且指定數據長度
[self.fileStream write:data.bytes maxLength:data.length];
// 計算當前數據下載完成的大小
self.recvedfileLength += data.length;
// 計算下載進度
float progress = (float)self.recvedfileLength / self.expectedContentLength;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[self.fileStream close];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// 關閉文件流
[self.fileStream close];
}
6.6 異步下載
// 下載文件的總長度
@property (nonatomic, assign) long long expectedContentLength;
// 當前文件大小
@property (nonatomic, assign) long long recvedfileLength;
// 輸出數據流
@property (nonatomic, strong) NSOutputStream *fileStream;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/download/file/minion_02.mp4"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
// 遵照協議 <NSURLConnectionDataDelegate>
[NSURLConnection connectionWithRequest:urlRequest delegate:self];
// 啓動運行循環
CFRunLoopRun();
});
// 協議方法
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"312.mp4"];
// 若是文件不存在,方法不會出錯
[[NSFileManager defaultManager] removeItemAtPath:documentsPath error:NULL];
// 以拼接的方式實例化文件流
self.fileStream = [[NSOutputStream alloc] initToFileAtPath:documentsPath append:YES];
// 打開文件流
[self.fileStream open];
// 獲取數據總大小
self.expectedContentLength = response.expectedContentLength;
self.recvedfileLength = 0;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// 將數據的 "字節"一次性寫入文件流,而且指定數據長度
[self.fileStream write:data.bytes maxLength:data.length];
// 計算當前數據下載完成的大小
self.recvedfileLength += data.length;
// 計算下載進度
float progress = (float)self.recvedfileLength / self.expectedContentLength;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// 關閉文件流
[self.fileStream close];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// 關閉文件流
[self.fileStream close];
}
七、NSURLConnection 下載單例封裝
7.1 QDownloaderOperation.h
@interface QDownloaderOperation : NSOperation
/// 類方法
+ (instancetype)downloaderWithURL:(NSURL *)url
progress:(void (^)(float progress))progress
successed:(void (^)(NSString *targetPath))successed
failed:(void (^)(NSError *error))failed;
/// 暫停當前下載
- (void)pauseDownload;
/// 取消當前下載
- (void)cancelDownload;
@end
7.2 QDownloaderOperation.m
@interface QDownloaderOperation () <NSURLConnectionDataDelegate>
/// 下載文件總長度
@property (nonatomic, assign) long long expectedContentLength;
/// 已下載文件大小
@property (nonatomic, assign) long long recvedfileLength;
/// 下載目標目錄
@property (nonatomic, copy) NSString *targetPath;
/// 下載文件輸出數據流
@property (nonatomic, strong) NSOutputStream *fileStream;
/// block 屬性
@property (nonatomic, copy) void (^progressBlock)(float);
@property (nonatomic, copy) void (^successedBlock)(NSString *);
@property (nonatomic, copy) void (^failedBlock)(NSError *);
/// 網絡鏈接屬性
@property (nonatomic, strong) NSURLConnection *conn;
@property (nonatomic, strong) NSURL *downloadURL;
@end
+ (instancetype)downloaderWithURL:(NSURL *)url progress:(void (^)(float))progress successed:(void (^)(NSString *))successed failed:(void (^)(NSError *))failed {
QDownloaderOperation *downloader = [[self alloc] init];
downloader.progressBlock = progress;
downloader.successedBlock = successed;
downloader.failedBlock = failed;
downloader.downloadURL = url;
return downloader;
}
- (void)main {
@autoreleasepool {
// 檢查服務器上的文件信息
[self checkServerFileInfoWithURL:self.downloadURL];
if (self.isCancelled) return;
// 檢查本地文件信息
long long fileSize = [self checkLocalFileInfo];
if (fileSize == self.expectedContentLength) {
// 下載完成的回調
if (self.successedBlock) {
dispatch_async(dispatch_get_main_queue(), ^{
self.successedBlock(self.targetPath);
});
// 下載進度的回調
if (self.progressBlock) {
self.progressBlock(1.0);
}
}
return;
}
// 根據本地文件的長度,從對應 "偏移" 位置開始下載
[self downloadWithURL:self.downloadURL offset:fileSize];
}
}
- (void)pauseDownload {
// 取消一個請求,調用此方法後,鏈接不在調用代理方法
[self.conn cancel];
}
- (void)cancelDownload {
[self.conn cancel];
[[NSFileManager defaultManager] removeItemAtPath:self.targetPath error:NULL];
}
/// 檢查服務器上的文件信息
- (void)checkServerFileInfoWithURL:(NSURL *)url {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"HEAD";
NSURLResponse *response = nil;
NSError *error = nil;
// 發送同步方法
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error == nil && response != nil) {
// 文件大小
self.expectedContentLength = response.expectedContentLength;
// 文件名
self.targetPath = [NSTemporaryDirectory() stringByAppendingPathComponent:response.suggestedFilename];
}
}
/// 檢查本地文件信息
- (long long)checkLocalFileInfo {
long long fileSize = 0;
// 檢查本地是否存在文件
if ([[NSFileManager defaultManager] fileExistsAtPath:self.targetPath]) {
NSDictionary *dict = [[NSFileManager defaultManager] attributesOfItemAtPath:self.targetPath error:NULL];
// 獲取文件大小
fileSize = [dict fileSize];
}
// 判斷是否比服務器的文件大
if (fileSize > self.expectedContentLength) {
// 刪除文件
[[NSFileManager defaultManager] removeItemAtPath:self.targetPath error:NULL];
fileSize = 0;
}
return fileSize;
}
/// 從斷點處開始下載
- (void)downloadWithURL:(NSURL *)url offset:(long long)offset {
// 記錄本地文件大小
self.recvedfileLength = offset;
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:1 timeoutInterval:15];
// 一旦設置了 Range,response 的狀態碼會變成 206
[urlRequest setValue:[NSString stringWithFormat:@"bytes=%lld-", offset] forHTTPHeaderField:@"Range"];
// 遵照協議 <NSURLConnectionDataDelegate>
self.conn = [NSURLConnection connectionWithRequest:urlRequest delegate:self];
[self.conn start];
// 開啓子線程運行循環
CFRunLoopRun();
}
/// 協議方法
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// 以拼接的方式實例化文件流
self.fileStream = [[NSOutputStream alloc] initToFileAtPath:self.targetPath append:YES];
// 打開文件流
[self.fileStream open];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// 將數據的 "字節" 一次性寫入文件流,而且指定數據長度
[self.fileStream write:data.bytes maxLength:data.length];
// 計算當前數據下載完成的大小
self.recvedfileLength += data.length;
// 計算下載進度
float progress = (float)self.recvedfileLength / self.expectedContentLength;
// 進度的回調
if (self.progressBlock) {
self.progressBlock(progress);
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// 關閉文件流
[self.fileStream close];
// 完成的回調
if (self.successedBlock) {
// 主線程回調
dispatch_async(dispatch_get_main_queue(), ^{
self.successedBlock(self.targetPath);
});
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// 關閉文件流
[self.fileStream close];
// 失敗的回調
if (self.failedBlock) {
self.failedBlock(error);
}
}
7.3 QDownloaderManager.h
@interface QDownloaderManager : NSObject
/// 單例
+ (instancetype)sharedManager;
/// 開始下載
- (void)downloadWithURL:(NSURL *)url progress:(void (^)(float progress))progress successed:(void (^)(NSString *targetPath))successed failed:(void (^)(NSError *error))failed;
/// 暫停下載
- (void)pauseWithURL:(NSURL *)url;
/// 取消下載
- (void)cancelWithURL:(NSURL *)url;
@end
7.4 QDownloaderManager.m
@interface QDownloaderManager ()
/// 下載操做緩衝池
@property (nonatomic, strong) NSMutableDictionary *downloadCache;
/// 下載操做隊列
@property (nonatomic, strong) NSOperationQueue *downloadQueue;
@end
+ (instancetype)sharedManager {
static id instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
- (void)downloadWithURL:(NSURL *)url progress:(void (^)(float))progress successed:(void (^)(NSString *))successed failed:(void (^)(NSError *))failed {
// 檢查緩衝池中是否有下載,若是有,直接返回
if (self.downloadCache[url.absoluteString] != nil) {
NSLog(@"正在在玩命下載中...");
return;
}
QDownloaderOperation *downloader = [QDownloaderOperation downloaderWithURL:url progress:progress successed:^(NSString *targetPath) {
// 刪除下載操做
[self.downloadCache removeObjectForKey:url.absoluteString];
if (successed != nil) {
successed(targetPath);
}
} failed:^(NSError *error) {
[self.downloadCache removeObjectForKey:url.absoluteString];
if (failed != nil) {
failed(error);
}
}];
// 添加到緩衝池
[self.downloadCache setObject:downloader forKey:url.absoluteString];
// 添加到隊列
[self.downloadQueue addOperation:downloader];
}
- (void)pauseWithURL:(NSURL *)url {
// 判斷緩衝池中是否有對應的下載操做
QDownloaderOperation *downloader = self.downloadCache[url.absoluteString];
if (downloader != nil) {
// 暫停 downloader 內部的 NSURLConnection
[downloader pauseDownload];
// 給操做發送取消消息 NSOperation
[downloader cancel];
// 從緩衝池中清除
[self.downloadCache removeObjectForKey:url.absoluteString];
}
}
- (void)cancelWithURL:(NSURL *)url {
// 判斷緩衝池中是否有對應的下載操做
QDownloaderOperation *downloader = self.downloadCache[url.absoluteString];
if (downloader != nil) {
// 取消 downloader 內部的 NSURLConnection
[downloader cancelDownload];
// 給操做發送取消消息 NSOperation
[downloader cancel];
// 從緩衝池中清除
[self.downloadCache removeObjectForKey:url.absoluteString];
}
}
/// 懶加載
- (NSMutableDictionary *)downloadCache {
if (_downloadCache == nil) {
_downloadCache = [NSMutableDictionary dictionary];
}
return _downloadCache;
}
- (NSOperationQueue *)downloadQueue {
if (_downloadQueue == nil) {
_downloadQueue = [[NSOperationQueue alloc] init];
// 設置最大併發數
_downloadQueue.maxConcurrentOperationCount = 5;
}
return _downloadQueue;
}
7.5 ViewController.m
// 下載進度
@property (weak, nonatomic) IBOutlet UIProgressView *progressView;
@property (nonatomic, strong) NSURL *url;
// 開始下載
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
self.url = url;
[[QDownloaderManager sharedManager] downloadWithURL:url progress:^(float progress) {
dispatch_async(dispatch_get_main_queue(), ^{
self.progressView.progress = progress;
});
} successed:^(NSString *targetPath) {
NSLog(@"%@", targetPath);
} failed:^(NSError *error) {
NSLog(@"%@", error);
}];
// 暫停下載
[[QDownloaderManager sharedManager] pauseWithURL:self.url];
// 取消下載
[[QDownloaderManager sharedManager] cancelWithURL:self.url];