项目中经常遇到多图片的上传需求,这个多文件上传的方法可以使用AFN中的一个方法,
AFNetWorking的作者在GitHub的介绍中列出了这个方法:
Creating an Upload Task for a Multi-Part Request, with Progress
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:@"http://example.com/upload" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileURL:[NSURL fileURLWithPath:@"file://path/to/image.jpg"] name:@"file" fileName:@"filename.jpg" mimeType:@"image/jpeg" error:nil];
} error:nil];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLSessionUploadTask *uploadTask;
uploadTask = [manager
uploadTaskWithStreamedRequest:request
progress:^(NSProgress * _Nonnull uploadProgress) {
// This is not called back on the main queue.
// You are responsible for dispatching to the main queue for UI updates
dispatch_async(dispatch_get_main_queue(), ^{
//Update the progress view
[progressView setProgress:uploadProgress.fractionCompleted];
});
}
completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
if (error) {
NSLog(@"Error: %@", error);
} else {
NSLog(@"%@ %@", response, responseObject);
}
}];
[uploadTask resume];
具体可以参照源码注释看下AFNetWorking作者的解释。
下面把结合我们业务的代码拿出来,说一下我们做多图片上传时的思路。
大体说一下:多个图片组合成数组,以uploadKeys区分每个图片,结合参数转成data添加到formData中创建任务请求,再将任务请求以数据流的形式上传。
- (void)uploadPhotoWithDataSource:(NSArray *)uploadDataSource parametersDic:(NSDictionary *)parametersDic uploadURI:(NSString *)uploadURI uploadKeys:(NSArray *)uploadKeys uploadMethod:(NSString *)uploadMethod uploadSingleSuccess:(YHShopkeeperUploadPhotoSuccess)uploadSingleSuccess allPhotosProgress:(YHShopkeeperUploadProgress)progress allRequestSucess:(YHShopkeeperAllUploadPhotoRequestSuccess)successBlock requestFailed:(YHShopkeeperAllUploadPhototRequestFailure)failedBlock
{
// 创建会话管理
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSString *token = [[NSUserDefaults standardUserDefaults] objectForKey:accessTokeKey];
// uploadURI为图片上传的地址
NSString *jsonStr = [self requireParameters:parametersDic uri:uploadURI requestParams:nil needRandom:NO];
NSString *urlStr = [NSString stringWithFormat:@"%@%@?access_token=%@&json=%@",BASE_URL,RESOURCES_URL,token,[jsonStr stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]];
// 创建多任务请求
// uploadMethod为上传方式,此处应为“POST”
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:uploadMethod URLString:urlStr parameters:@{@"json" : jsonStr} constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
// 多图片,所以使用for循环把每个图片转成NSData的形式添加到formData
for (int i = 0; i<uploadDataSource.count; i++) {
UIImage *image = uploadDataSource[i];
// 使用时间给每个图片命名
// 1) 创建data对象
NSDate *date = [NSDate date];
// 2) 使用日期格式化工具
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
// 3) 指定日期格式
[formatter setDateFormat:@"yyyyMMddHHmmss"];
NSString *dateStr = [formatter stringFromDate:date];
// 4) 使用系统时间生成一个文件名
NSString *fileName = [NSString stringWithFormat:@"%@.png", dateStr];
// 压缩图片
NSData *data = UIImageJPEGRepresentation(image, 1);
if (data.length>100*1024) {
if (data.length>1024*1024) {//1M以及以上
data=UIImageJPEGRepresentation(image, 0.1);
}else if (data.length>512*1024) {//0.5M-1M
data=UIImageJPEGRepresentation(image, 0.5);
}else if (data.length>200*1024) {//0.25M-0.5M
data=UIImageJPEGRepresentation(image, 0.9);
}
}
// uploadKeys为一个数组,存放的是不同图片的路径,后台以路径判别是哪个图片
[formData appendPartWithFileData:data name:uploadKeys[i] fileName:fileName mimeType:@"image/jpeg"];
}
} error:nil];
// 创建上传会话任务
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:^(NSProgress * _Nonnull uploadProgress) {
// 进度回调
if (progress) {
progress(uploadProgress);
}
} completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
// 错误回调
if (responseObject[@"errMsg"] || error || !responseObject)
{
if (failedBlock)
{
failedBlock(error,responseObject[@"errMsg"]);
}
}
else
{
// 成功回调
if (successBlock) {
successBlock(responseObject);
}
}
[manager invalidateSessionCancelingTasks:NO];
}];
[uploadTask resume];
}