之所以總結(jié)一下, 是因?yàn)榫W(wǎng)上搜到的寫(xiě)的并不太好, 特此整理一下, 包含單文件上傳, 多文件并行上傳, 多文件串行上傳
傳遞格式
dictionary包含了name, filename, data 分別對(duì)應(yīng)對(duì)象句柄變量名, 傳遞文件名, 傳遞文件二進(jìn)制/本地url
全部使用multipart/form-data表單模擬上傳
默認(rèn)params都通過(guò)字典傳遞, 并且都使用post方式發(fā)送變量參數(shù)
單文件上傳
我對(duì)其進(jìn)行了少許修改, 如果發(fā)的data類型是nsdata或者是nsurl, 進(jìn)入不同的api, 這里并沒(méi)有特別的
+(NSURLSessionUploadTask*)uploadTaskUrl:(NSURL*)uploadPage params:(NSDictionary*)params file:(NSDictionary<NSString*,id>*)unitData completion:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionBlock {
// 構(gòu)造 NSURLRequest
NSLog(@"url %@\nparam %@",uploadPage,params);
NSError* error = NULL;
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:[uploadPage absoluteString] parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
if (unitData && [unitData objectForKey:@"key"] && [unitData objectForKey:@"filename"] && [unitData objectForKey:@"data"]) {
if ([[unitData objectForKey:@"data"] isKindOfClass:[NSData class]]) {
[formData appendPartWithFileData:(NSData*)[unitData objectForKey:@"data"] name:[unitData objectForKey:@"key"] fileName:[unitData objectForKey:@"filename"] mimeType:@"multipart/form-data"];
}else if([[unitData objectForKey:@"data"] isKindOfClass:[NSURL class]]){
[formData appendPartWithFileURL:(NSURL*)[unitData objectForKey:@"data"] name:[unitData objectForKey:@"key"] fileName:[unitData objectForKey:@"filename"] mimeType:@"multipart/form-data" error:nil];
}
}
} error:&error];
NSLog(@"error %@",error);
// 可在此處配置驗(yàn)證信息
// 將 NSURLRequest 與 completionBlock 包裝為 NSURLSessionUploadTask
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:^(NSProgress * _Nonnull uploadProgress) {
} completionHandler:completionBlock];
return uploadTask;
}
多文件串行上傳 (不推薦)
對(duì)接口進(jìn)行多次調(diào)用, 每次只傳一個(gè)文件, 通過(guò)線程控制序列, 缺點(diǎn)是返回多個(gè)結(jié)果, 因?yàn)槭嵌啻畏?wù)器交互訪問(wèn), 這也是從網(wǎng)上找下來(lái)的, 網(wǎng)上可以搜到一大片, 關(guān)于多文件上傳, 大概有2~3種這樣做的方法, 個(gè)人認(rèn)為既然官方支持append api, 那么就說(shuō)明插入的數(shù)據(jù)是可以多重的, 也就有了并行上傳的方法, 不需要再管進(jìn)程的事更方便
+(void)uploadTasks:(NSURL*)uploadPage files:(NSArray<NSDictionary<NSString*,id>*>*)arrFiles progress:(void(^)(float progress))onProgress complete:(void(^)(NSArray<NSDictionary*>* result))onComplete error:(void(^)(NSError* error))onError{
// 需要上傳的數(shù)據(jù)
// 準(zhǔn)備保存結(jié)果的數(shù)組,元素個(gè)數(shù)與上傳的圖片個(gè)數(shù)相同胞四,先用 NSNull 占位
NSMutableArray* result = [NSMutableArray array];
for (NSInteger i=arrFiles.count;i>0;i--) {
[result addObject:[NSNull null]];
}
dispatch_group_t group = dispatch_group_create();
for (NSInteger i = 0; i < arrFiles.count; i++) {
dispatch_group_enter(group);
NSURLSessionUploadTask* uploadTask = [self uploadTaskUrl:uploadPage params:@{} file:arrFiles[i] completion:^(NSURLResponse *response, NSDictionary* responseObject, NSError *error) {
onProgress((float)i/arrFiles.count);
if (error) {
NSLog(@"第 %d 張圖片上傳失敗: %@", (int)i + 1, error);
onError(error);
dispatch_group_leave(group);
} else {
NSLog(@"第 %d 張圖片上傳成功: %@", (int)i + 1, responseObject);
@synchronized (result) { // NSMutableArray 是線程不安全的娇钱,所以加個(gè)同步鎖
result[i] = responseObject;
}
dispatch_group_leave(group);
}
}];
[uploadTask resume];
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"上傳完成!");
for (id response in result) {
NSLog(@"%@", response);
}
onComplete(result);
});
}
多文件并行上傳 (推薦)
所謂并行上傳, 也就是對(duì)同一個(gè)接口同時(shí)傳遞多個(gè)二進(jìn)制文件/url, 因?yàn)橛械臅r(shí)候是需要實(shí)現(xiàn)這一功能的, 同時(shí)上傳多個(gè)文件但只需一次服務(wù)器訪問(wèn)
+(NSURLSessionUploadTask*)uploadTaskUrl:(NSURL*)uploadPage params:(NSDictionary*)params files:(NSArray<NSDictionary<NSString*,id>*>*)fileDatas completion:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionBlock {
NSLog(@"url %@\nparam %@",uploadPage,params);
NSError* error = NULL;
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:[uploadPage absoluteString] parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
for (int i=0; i<fileDatas.count; i++) {
NSDictionary* unitData = fileDatas[i];
if (unitData && [unitData objectForKey:@"key"] && [unitData objectForKey:@"filename"] && [unitData objectForKey:@"data"]) {
if ([[unitData objectForKey:@"data"] isKindOfClass:[NSData class]]) {
[formData appendPartWithFileData:(NSData*)[unitData objectForKey:@"data"] name:[unitData objectForKey:@"key"] fileName:[unitData objectForKey:@"filename"] mimeType:@"multipart/form-data"];
}else if([[unitData objectForKey:@"data"] isKindOfClass:[NSURL class]]){
[formData appendPartWithFileURL:(NSURL*)[unitData objectForKey:@"data"] name:[unitData objectForKey:@"key"] fileName:[unitData objectForKey:@"filename"] mimeType:@"multipart/form-data" error:nil];
}
}
}
} error:&error];
NSLog(@"error %@",error);
// 將 NSURLRequest 與 completionBlock 包裝為 NSURLSessionUploadTask
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:^(NSProgress * _Nonnull uploadProgress) {
} completionHandler:completionBlock];
return uploadTask;
}
喜歡就收藏個(gè)吧, 順便投個(gè)幣