使用 AFNetworking 2.0 上传进度
Posted
技术标签:
【中文标题】使用 AFNetworking 2.0 上传进度【英文标题】:Upload progress with AFNetworking 2.0 【发布时间】:2014-06-17 11:22:23 【问题描述】:我知道这个问题在这个网站上很受欢迎,但是在搜索了大部分答案后,我找不到解决方案。 我的应用程序是将图像上传到远程 url。我尝试了几种上传方式,都成功了: (1) 使用 AFURLSessionManager
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[(AFHTTPResponseSerializer*)manager.responseSerializer setAcceptableContentTypes:[NSSet setWithObjects:@"multipart/form-data", nil]];
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error)
if (error)
NSDictionary *userInfo=[error userInfo];
id responseError=[userInfo objectForKey:@"AFNetworkingOperationFailingURLResponseErrorKey"];
if ([responseError isKindOfClass:[NSHTTPURLResponse class]])
NSHTTPURLResponse *reponse=(NSHTTPURLResponse*)responseError;
if (reponse.statusCode==200)
result(YES);
else
result(NO);
else
result(NO);
else
result(YES);
];
[uploadTask resume];
为此,我使用 KVO 来监控进度,但没有运气。
(2) 使用AFHTTPRequestOperation
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite)
NSLog(@"total bytes written: %lld",totalBytesWritten);
];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
result(YES);
failure:^(AFHTTPRequestOperation *operation, NSError *error)
if (operation.response.statusCode==200)
result(YES);
else
result(NO);
];
[operation start];
仅在开始上传时立即显示日志“写入的总字节数:”一次,文件体积为 100%。
(3) 使用 AFHTTPRequestOperationManager
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
AFHTTPRequestOperation *operation =
[manager HTTPRequestOperationWithRequest:request
success:^(AFHTTPRequestOperation *operation, id responseObject)
NSLog(@"Success %@", responseObject);
result(YES);
failure:^(AFHTTPRequestOperation *operation, NSError *error)
if (operation.response.statusCode==200)
result(YES);
else
result(NO);
];
// 4. Set the progress block of the operation.
[operation setUploadProgressBlock:^(NSUInteger __unused bytesWritten,
long long totalBytesWritten,
long long totalBytesExpectedToWrite)
double percentDone = (double)totalBytesWritten / (double)totalBytesExpectedToWrite;
NSLog(@"progress updated(percentDone) : %f", percentDone);
];
// 5. Begin!
[operation start];
=> 与第二个解决方案的结果相同。
请注意,所有解决方案都已成功上传,但进度未更新(NSProgress
或阻止)。
【问题讨论】:
【参考方案1】:NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:@"<your upload url>" parameters:@<parameters dict> constructingBodyWithBlock:^(id<AFMultipartFormData> formData)
_STRONGREF(strongSelf);
NSString *name=@"file_data_name";
[formData appendPartWithFileURL:[NSURL fileURLWithPath:path] name:name fileName:<file Path> mimeType:@"image/png" error:nil];//u can use data as well with other method
error:nil];
[request setTimeoutInterval:180];
[request setValue:@"VAlue_your" forHTTPHeaderField:@"feild"];//set headers
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSProgress *progress = nil;
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error)
if (error)
NSLog(@"Error: %@", error);
else
NSLog(@"%@ %@", response, responseObject);
];
NSLog(@"%@",progress);
[uploadTask resume];
我的宏是
#define _WEAKREF(obj) __weak typeof(obj)ref=obj;
#define _STRONGREF(name) __strong typeof(ref)name=ref;\
if(!name)return ;\
【讨论】:
【参考方案2】:在你的 NSProgress 上设置一个观察者。
类似
[uploadTask resume];
[progress addObserver:self
forKeyPath:@"fractionCompleted"
options:NSKeyValueObservingOptionNew
context:NULL];
然后执行
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
if ([keyPath isEqualToString:@"fractionCompleted"])
NSProgress *progress = (NSProgress *)object;
NSLog(@"progress = %f", progress.fractionCompleted);
else
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
上传任务完成后别忘了移除观察者。
注意:progress.fractionCompleted 返回一个百分比值。以 MB 为单位由您决定。
【讨论】:
谢谢,但我在我的项目中使用了 bove 代码(KVO-Key 值观察器)。我不知道为什么观察者不开火。【参考方案3】:最后,我找到了没有调用进度块的原因:我上传了一个非常小的图像,大约只有几十 Kb。我尝试上传更大尺寸的文件并调用进度块。根据我的经验,带有 NSProgress 的 KVO 不起作用。取而代之的是,我们可以使用 AFHTTPRequestOperation 或 AFHTTPRequestOperationManager。如果您喜欢手动上传,您可以使用How can I upload a photo to a server with the iPhone? 建议的 NSURLConnection 以及委托方法:
- (void)connection:(NSURLConnection *)connection
didSendBodyData:(NSInteger)bytesWritten
totalBytesWritten:(NSInteger)totalBytesWritten
totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
NSLog(@"percent: %d",100*totalBytesWritten/totalBytesExpectedToWrite);
【讨论】:
我按照您的建议上传了一个更大的文件,并且正在调用委托连接:didSendBodyData 也打印了日志。但是 1) 委托中的 self.uploadProgress 为 nil,因此未调用回调块 setUploadProgressBlock。 2) AFURLConnectionOperation.m 中的调试描述了 self.uploadProgress 的内容,而 setUploadProgressBlock 在委托中变为 nil。以上是关于使用 AFNetworking 2.0 上传进度的主要内容,如果未能解决你的问题,请参考以下文章
AFNetworking 上传进度发送 SOAP NSData
在单个 PHP 中使用 AFNetworking 2.0 上传图像和信息(两者)