我尝试使用AFNetworking和NSProgress跟踪HTTP请求的进度。基本上,我的请求是一个包含文本参数和图像数据的多部分表单数据,所有这些都在一个块中。
这是我上传任务的代码,对我来说似乎很简单和正常:
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:@"<THE_API_URL>" parameters:nil constructingBodyWithBlock:constructionBlock];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
NSProgress *progress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
[progress addObserver:self forKeyPath:@"fractionCompleted" options:NSKeyValueObservingOptionNew context:NULL];
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
// UI reacts to error
} else {
// Do stuff here
}
}];
[uploadTask resume];
现在,我不明白的是,即使上传任务完成并成功,回调观察者方法也不会被调用。有人可以帮我理解为什么吗?这是我的代码。
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
if ([keyPath isEqualToString:@"fractionCompleted"] && [object isKindOfClass:[NSProgress class]]) {
NSProgress *progress = (NSProgress *)object;
NSLog(@"Progress is: %f", progress.fractionCompleted);
}
}
更新:我按照AFNetworking的uploadTaskWithStreamedRequest:...
方法代码,发现他们实际上是从NSProgress
内部替换uploadTaskWithTask:...
对象。当然,如果使NSProgress
指针指向新实例,则不会注册该新实例以观察fractionCompleted
属性。如何在不修改AFNetworking代码的情况下对这个新的NSProgress
实例进行键值观察?
答案 0 :(得分:7)
所有你需要做的就是将观察者移动到创建上传任务之后,它就像魅力一样。
NSProgress *progress;
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
// UI reacts to error
} else {
// Do stuff here
}
}];
[uploadTask resume];
[progress addObserver:self forKeyPath:@"fractionCompleted" options:NSKeyValueObservingOptionNew context:NULL];
答案 1 :(得分:5)
我放弃了跟踪AFURLSessionManager
进度的方法。相反,我使用了一个很好的旧AFHTTPRequestOperation
。
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:@"THE_API_URL" parameters:nil constructingBodyWithBlock:constructionBlock];
AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperationManager manager] HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
// Do stuff here
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// Catch error
}];
[requestOperation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
double percentDone = (double)totalBytesWritten / (double)totalBytesExpectedToWrite;
progressBlock(percentDone);
}];
[requestOperation start];
答案 2 :(得分:1)
您可能遇到此问题https://github.com/AFNetworking/AFNetworking/issues/1398,这实际上是由于NSURLSession中的设计限制。在讨论结束时,您将看到建议的解决方法。我正在使用此解决方法并观察&#34; fractionCompleted&#34;对我来说很好。
-Brian