2025-05-23

最近在做一個小項目的時候,發現使用NSURLSession或者AFNNetworking進行斷點續傳時諸多的不便,於是自己封裝瞭一個類來實現斷點續傳,在程序重新啟動時仍然可以繼續下載(需自己調用方法),同時可以在同一時間多次調用該類方法。使用時請註意傳入各參數的合理性,方法內部並沒有對傳入的參數進行修正

 

主要技術: NSURLConnection、block、NFFileHandle

 

1、首先,我提供一個類方法,供外界調用。 創建的類名為DownloadService

 

復制代碼

 1 //

 2 //  DownloadService.h

 3 //  11111

 4 //

 5 //  Created by Liu Feng on 14-2-17.

 6 //  Copyright (c) 2014年 Liu Feng. All rights reserved.

 7 //

 8 

 9 #import <Foundation/Foundation.h>

10 

11 typedef void (^DownloadServiceSuccess)(NSString *savePath);

12 typedef void (^DownloadServiceFailure)(NSError *error);

13 

14 @interface DownloadService : NSObject

15 /**

16  *  下載指定URL的資源到路徑

17  *

18  *  @param urlStr   網絡資源路徑

19  *  @param toPath   本地存儲文件夾

20  *  @param capacity 緩存大小,單位為Mb

21  *  @param success  成功時回傳本地存儲路徑

22  *  @param failure  失敗時回調的錯誤原因

23  */

24 + (void)downLoadWithURL:(NSString *)urlStr toDirectory:(NSString *)toDirectory cacheCapacity:(NSUInteger)capacity  success:(DownloadServiceSuccess)success failure:(DownloadServiceFailure)failure;

25 

26 @end

復制代碼

 

 

2、在.m中實現

 

復制代碼

  1 //

  2 //  DownloadService.m

  3 //  11111

  4 //

  5 //  Created by Liu Feng on 14-2-17.

  6 //  Copyright (c) 2014年 Liu Feng. All rights reserved.

  7 //

  8 

  9 #import "DownloadService.h"

 10 

 11 static DownloadService *_download;

 12 static NSMutableDictionary *_dictPath;

 13 static NSMutableDictionary *_dictBlock;

 14 static NSMutableDictionary *_dictHandle;

 15 static unsigned long long _cacheCapacity; // 緩存

 16 static NSMutableData *_cacheData;

 17 

 18 typedef void (^myBlcok)(NSString *savePath, NSError *error);

 19 

 20 @interface DownloadService ()<NSURLConnectionDataDelegate>

 21 

 22 @end

 23 

 24 @implementation DownloadService

 25 

 26 + (void)initialize

 27 {

 28     _download = [[DownloadService alloc] init];

 29     _dictPath = [NSMutableDictionary dictionary]; // 存儲文件路徑

 30     _dictBlock = [NSMutableDictionary dictionary]; // 存儲block

 31     _dictHandle = [NSMutableDictionary dictionary]; // 存儲NSFileHandle對象

 32     _cacheData = [NSMutableData data]; // 存放緩存

 33 }

 34 

 35 + (void)downLoadWithURL:(NSString *)urlStr toDirectory:(NSString *)toDirectory cacheCapacity:(NSInteger)capacity success:(DownloadServiceSuccess)success failure:(DownloadServiceFailure)failure{

 36     

 37     // 1. 創建文件

 38     NSString *fileName = [urlStr lastPathComponent];

 39     NSString *filePath = [NSString stringWithFormat:@"%@/%@", toDirectory, fileName];

 40     

 41     // 記錄文件起始位置

 42     unsigned long long from = 0;

 43     if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]){ // 已經存在

 44         from = [[NSData dataWithContentsOfFile:filePath] length];

 45     }else{ // 不存在,直接創建

 46         [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];

 47     }

 48     

 49     // url

 50     NSURL *url = [NSURL URLWithString:urlStr];

 51     

 52     // 請求

 53     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0f];

 54     

 55     // 設置請求頭文件

 56     NSString *rangeValue = [NSString stringWithFormat:@"bytes=%llu-", from];

 57     [request addValue:rangeValue forHTTPHeaderField:@"Range"];

 58     

 59     // 創建連接

 60     NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:_download];

 61     

 62     // 保存文章連接

 63     _dictPath[connection.description] = filePath;

 64     

 65     // 保存block,用於回調

 66     myBlcok block = ^(NSString *savePath, NSError *error){

 67         if (error) {

 68             if (failure) {

 69                 failure(error);

 70             }

 71         }else{

 72             if (success) {

 73                 success(savePath);

 74             }

 75         }

 76     };

 77     _dictBlock[connection.description] = block;

 78     

 79     // 保存緩存大小

 80     _cacheCapacity = capacity * 1024 * 1024;

 81     

 82     // 開始連接

 83     [connection start];

 84 }

 85 /**

 86  *  接收到服務器響應

 87  *

 88  *  @param connection 哪一個連接

 89  *  @param response   響應對象

 90  */

 91 – (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response

 92 {

 93     // 取出文章地址

 94     NSString *filePath = _dictPath[connection.description];

 95     

 96     // 打開文件準備輸入

 97     NSFileHandle *outFile = [NSFileHandle fileHandleForWritingAtPath:filePath];

 98     

 99     // 保存文件操作對象

100     _dictHandle[connection.description] = outFile;

101 }

102 /**

103  *  開始接收數據

104  *

105  *  @param connection 哪一個連接

106  *  @param data       二進制數據

107  */

108 – (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

109 {

110     // 取出文件操作對象

111     NSFileHandle *outFile = _dictHandle[connection.description];

112     

113     // 移動到文件結尾

114     [outFile seekToEndOfFile];

115     

116     // 保存數據

117     [_cacheData appendData:data];

118     

119     if (_cacheData.length >= _cacheCapacity) {

120         // 寫入文件

121         [outFile writeData:data];

122         

123         // 清空數據

124         [_cacheData setLength:0];

125     }

126 }

127 /**

128  *  連接出錯

129  *

130  *  @param connection 哪一個連接出錯

131  *  @param error      錯誤信息

132  */

133 – (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error

134 {

135     // 取出文件操作對象

136     NSFileHandle *outFile = _dictHandle[connection.description];

137     

138     // 關閉文件操作

139     [outFile closeFile];

140     

141     // 回調block

142     myBlcok block = _dictBlock[connection.description];

143     

144     if (block) {

145         block(nil, error);

146     }

147     

148     // 移除字典中

149     [_dictHandle removeObjectForKey:connection.description];

150     [_dictPath removeObjectForKey:connection.debugDescription];

151     [_dictBlock removeObjectForKey:connection.description];

152 }

153 /**

154  *  結束加載

155  *

156  *  @param connection 哪一個連接

157  */

158 – (void)connectionDidFinishLoading:(NSURLConnection *)connection

159 {

160     // 取出文件操作對象

161     NSFileHandle *outFile = _dictHandle[connection.description];

162     

163     // 關閉文件操作

164     [outFile closeFile];

165     

166     // 取出路徑

167     NSString *savePath = [_dictPath objectForKey:connection.description];

168     

169     // 取出block

170     myBlcok block = _dictBlock[connection.description];

171 

172     // 回調

173     if (block) {

174         block(savePath, nil);

175     }

176     

177     // 移除字典中

178     [_dictHandle removeObjectForKey:connection.description];

179     [_dictPath removeObjectForKey:connection.debugDescription];

180     [_dictBlock removeObjectForKey:connection.description];

181 }

182 

183 

184 @end 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *