@@ -129,6 +129,11 @@ - (void)addRequest:(ZHRequest *)request {
129
129
}
130
130
}
131
131
132
+ // 请求即将开始回调
133
+ if ([request.delegate respondsToSelector: @selector (requestWillStart )]) {
134
+ [request.delegate requestWillStart ];
135
+ }
136
+
132
137
[sessionTask resume ];
133
138
134
139
Lock;
@@ -143,7 +148,24 @@ - (NSURLSessionTask *)sessionTask4Request:(ZHRequest *)request {
143
148
NSDictionary *params = request.params ;
144
149
NSURLSessionTask *task = nil ;
145
150
NSError *error = nil ;
146
- task = [self dataTask4Request: request requestSerializer: requestSerializer urlStr: urlStr params: params constructingBlock: request.formData error: error];
151
+
152
+ NSString *method = @" GET" ;
153
+ switch (request.requestType ) {
154
+ case ZHRequest_Type_GET:
155
+ if (request.downloadPath ) {
156
+ return [self downloadTaskWithRequest: request downloadPath: request.downloadPath requestSerializer: requestSerializer url: request.urlString params: params downloadProcess: request.downloadProcess];
157
+ } else {
158
+ method = @" GET" ;
159
+ }
160
+ break ;
161
+ case ZHRequest_Type_POST:
162
+ method = @" POST" ;
163
+ break ;
164
+ default :
165
+ break ;
166
+ }
167
+
168
+ task = [self dataTask4Request: request method: method requestSerializer: requestSerializer urlStr: urlStr params: params constructingBlock: request.formData error: error];
147
169
148
170
return task;
149
171
}
@@ -177,25 +199,16 @@ - (AFHTTPRequestSerializer *)requestSerializer4Request:(ZHRequest *)request {
177
199
178
200
}
179
201
180
- - (NSURLSessionDataTask *)dataTask4Request : (ZHRequest *)request requestSerializer : (AFHTTPRequestSerializer *)serializer
181
- urlStr : (NSString *)url
182
- params : (id )params
183
- constructingBlock : (ConstructingFormDataBlock)formdata
184
- error : (NSError *)error {
202
+ - (NSURLSessionDataTask *)dataTask4Request : (ZHRequest *)request
203
+ method : (NSString *)method
204
+ requestSerializer : (AFHTTPRequestSerializer *)serializer
205
+ urlStr : (NSString *)url
206
+ params : (id )params
207
+ constructingBlock : (ConstructingFormDataBlock)formdata
208
+ error : (NSError *)error {
185
209
186
210
NSMutableURLRequest *urlRequest = nil ;
187
- NSString *method = @" GET" ;
188
- switch (request.requestType ) {
189
- case ZHRequest_Type_GET:
190
- method = @" GET" ;
191
- break ;
192
- case ZHRequest_Type_POST:
193
- method = @" POST" ;
194
- break ;
195
- default :
196
- break ;
197
- }
198
-
211
+
199
212
if (formdata) {
200
213
urlRequest = [serializer multipartFormRequestWithMethod: method URLString: url parameters: params constructingBodyWithBlock: formdata error: &error];
201
214
} else {
@@ -210,6 +223,61 @@ - (NSURLSessionDataTask *)dataTask4Request:(ZHRequest *)request requestSerialize
210
223
return dataTask;
211
224
}
212
225
226
+ /* !
227
+ @method
228
+ @abstract 返回下载任务
229
+ @discussion request 对应的request,传递responseObj 为fileurl,
230
+ 传递request 是为了给request中的各个属性赋值 如果 responseStr,responseData等。
231
+ */
232
+ - (NSURLSessionDownloadTask *)downloadTaskWithRequest : (ZHRequest *)request
233
+ downloadPath : (NSString *)path
234
+ requestSerializer : (AFHTTPRequestSerializer *)requestSerializer
235
+ url : (NSString *)url
236
+ params : (NSDictionary *)params
237
+ downloadProcess : (DownloadProcessBlock)process {
238
+ // 添加请求参数
239
+ NSMutableURLRequest *urlRequest = [requestSerializer requestWithMethod: @" GET" URLString: url parameters: params error: nil ];
240
+
241
+ // 保证下载路径 是一个路径,而不是文件夹
242
+ BOOL isDirectory = NO ;
243
+ if (![[NSFileManager defaultManager ] fileExistsAtPath: path isDirectory: &isDirectory]) {
244
+ isDirectory = NO ;
245
+ }
246
+ NSString *targetDownloadPath = nil ;
247
+ if (isDirectory) {
248
+ NSString *fileName = [urlRequest.URL lastPathComponent ];
249
+ targetDownloadPath = [NSString pathWithComponents: @[path, fileName]];
250
+ }
251
+
252
+ if ([[NSFileManager defaultManager ] fileExistsAtPath: targetDownloadPath]) {
253
+ // AFN use `moveItemAtURL` to move downloaded file to target path,
254
+ // this method aborts the move attempt if a file already exist at the path.
255
+ // So we remove the exist file before we start the download task.
256
+ // https://github.com/AFNetworking/AFNetworking/issues/3775
257
+ [[NSFileManager defaultManager ] removeItemAtPath: targetDownloadPath error: nil ];
258
+ }
259
+
260
+ NSURL *resumeDataUrl = [self incompleteDownloadTempPathForDownloadPath: path];
261
+ NSData *resumeData = [NSData dataWithContentsOfURL: resumeDataUrl];
262
+
263
+ BOOL isValid = [self validateResumeData: resumeData];
264
+
265
+
266
+ if (resumeData && isValid) {
267
+ return [self .manager downloadTaskWithResumeData: resumeData progress: process destination: ^NSURL * _Nonnull (NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
268
+ return [NSURL fileURLWithPath: targetDownloadPath isDirectory: NO ];
269
+ } completionHandler: ^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
270
+ [self handleResult: request urlResponse: response responseObj: filePath error: error];
271
+ }];
272
+ } else {
273
+ return [self .manager downloadTaskWithRequest: urlRequest progress: process destination: ^NSURL * _Nonnull (NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
274
+ return [NSURL fileURLWithPath: targetDownloadPath isDirectory: NO ];
275
+ } completionHandler: ^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
276
+ [self handleResult: request urlResponse: response responseObj: filePath error: error];
277
+ }];
278
+ }
279
+
280
+ }
213
281
214
282
- (void )handleResult : (ZHRequest *)request urlResponse : (NSURLResponse *)response responseObj : (id )responseObj error : (NSError *)error {
215
283
@@ -218,34 +286,66 @@ - (void)handleResult:(ZHRequest *)request urlResponse:(NSURLResponse *)response
218
286
request.allHeaderFields = httpResponse.allHeaderFields ;
219
287
220
288
request.responseObj = responseObj;
289
+
290
+ NSError *serializerError = nil ;
291
+
221
292
if ([responseObj isKindOfClass: [NSData class ]]) {
222
- request.responseObj = responseObj;
223
- NSError *serializerError = nil ;
293
+ request.responseData = responseObj;
294
+
224
295
switch (request.responseSerilalizerType ) {
225
296
case ZHRequest_ResponseSerilalizerType_JSON:
226
297
request.responseObj = [self .jsonResponseSerializer responseObjectForResponse: response data: responseObj error: &serializerError];
227
- request.responseString = [[NSString alloc ] initWithData: responseObj encoding: NSUTF8StringEncoding];
228
298
break ;
229
299
case ZHRequest_ResponseSerilalizerType_HTTP:
230
300
//
231
301
request.responseObj = [self .httpResponseSerializer responseObjectForResponse: response data: responseObj error: &serializerError ];
232
- request.responseString = [[NSString alloc ] initWithData: responseObj encoding: NSUTF8StringEncoding];
233
302
break ;
234
303
case ZHRequest_ResponseSerilalizerType_XML:
235
304
//
236
305
break ;
237
306
default :
238
307
break ;
239
308
}
309
+ if ([responseObj isKindOfClass: [NSData class ]]) {
310
+ request.responseString = [[NSString alloc ] initWithData: responseObj encoding: NSUTF8StringEncoding];
311
+ } else if ([responseObj isKindOfClass: [NSURL class ]]) { // 如果是下载任务
312
+ request.responseString = [((NSURL *)responseObj) absoluteString ];
313
+ }
240
314
}
241
- }
242
-
243
-
244
-
245
-
246
-
247
315
316
+
317
+ // TODO 返回结果校验
318
+ BOOL isValidResponse = NO ;
319
+ if (request.statusCode <= 200 && request.statusCode <= 400 ) {
320
+ isValidResponse = YES ;
321
+ }
322
+
323
+ BOOL isSuccess = NO ;
324
+ if (!error && !serializerError && isValidResponse) {
325
+ isSuccess = YES ;
326
+ }
327
+
328
+ if (isSuccess) {
329
+ // / 请求成功回调
330
+ if ([request.delegate respondsToSelector: @selector (requestFinished:responseObj: )]) {
331
+ [request.delegate requestFinished: request responseObj: request.responseObj];
332
+ }
333
+ if ([request.delegate respondsToSelector: @selector (requestFinished:responseStr: )]) {
334
+ [request.delegate requestFinished: request responseStr: request.responseString];
335
+ }
336
+ } else {
337
+ if ([request.delegate respondsToSelector: @selector (requestFailed: )]) {
338
+ [request.delegate requestFailed: error];
339
+ }
340
+ }
341
+ }
248
342
343
+ - (void )requestDidSuccessWithRequest : (ZHRequest *)request responseObj : (id )responseObj {
344
+
345
+ }
346
+ - (void )requestDidFailedWithRequest : (ZHRequest *)request error : (NSError *)error {
347
+
348
+ }
249
349
250
350
251
351
- (void )cancelRequest : (ZHRequest *)request {
@@ -273,4 +373,50 @@ - (void)cancelAllRequest {
273
373
}
274
374
}
275
375
376
+
377
+ #pragma mark - Resumable Download
378
+
379
+ - (NSURL *)incompleteDownloadTempPathForDownloadPath : (NSString *)downloadPath {
380
+ NSString *tempPath = [[self incompleteDownloadTempCacheFolder ] stringByAppendingPathComponent: downloadPath];
381
+ return [NSURL fileURLWithPath: tempPath];
382
+ }
383
+
384
+ - (NSString *)incompleteDownloadTempCacheFolder {
385
+ NSFileManager *fileManager = [NSFileManager new ];
386
+ static NSString *cacheFolder;
387
+
388
+ if (!cacheFolder) {
389
+ NSString *cacheDir = NSTemporaryDirectory ();
390
+ cacheFolder = [cacheDir stringByAppendingPathComponent: @" incomplete" ];
391
+ }
392
+
393
+ NSError *error = nil ;
394
+ if (![fileManager createDirectoryAtPath: cacheFolder withIntermediateDirectories: YES attributes: nil error: &error]) {
395
+ NSLog (@" Failed to create cache directory at %@ " , cacheFolder);
396
+ cacheFolder = nil ;
397
+ }
398
+ return cacheFolder;
399
+ }
400
+
401
+ - (BOOL )validateResumeData : (NSData *)data {
402
+ // From http://stackoverflow.com/a/22137510/3562486
403
+ if (!data || [data length ] < 1 ) return NO ;
404
+
405
+ NSError *error;
406
+ NSDictionary *resumeDictionary = [NSPropertyListSerialization propertyListWithData: data options: NSPropertyListImmutable format: NULL error: &error];
407
+ if (!resumeDictionary || error) return NO ;
408
+
409
+ // Before iOS 9 & Mac OS X 10.11
410
+ #if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED < 90000)\
411
+ || (defined (__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED < 101100 )
412
+ NSString *localFilePath = [resumeDictionary objectForKey: @" NSURLSessionResumeInfoLocalPath" ];
413
+ if ([localFilePath length ] < 1 ) return NO ;
414
+ return [[NSFileManager defaultManager ] fileExistsAtPath: localFilePath];
415
+ #endif
416
+ // After iOS 9 we can not actually detects if the cache file exists. This plist file has a somehow
417
+ // complicated structue. Besides, the plist structure is different between iOS 9 and iOS 10.
418
+ // We can only assume that the plist being successfully parsed means the resume data is valid.
419
+ return YES ;
420
+ }
421
+
276
422
@end
0 commit comments