NSProgress fractionCompleted键值观察方法未调用

时间:2014-02-10 11:28:19

标签: ios iphone objective-c ipad cocoa-touch

我尝试使用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实例进行键值观察?

3 个答案:

答案 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