Getting Download progress with AFNetworking 2.0 + NSProgress + Custom ProgressView
afnetworking-2, ios, ios7, iphone, objective-c
Solution
Use AFURLConnectionOperation -setDownloadProgressBlock:, updating the progress with the ratio of totalBytesRead over totalBytesExpectedToRead each time the block is called.
To update your UI element, just call the update through the main thread:
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
});
Problem
i'm getting confused trying to get progress from a Download Task with AFNetworking 2.0. I created a singleton object where I centralized my download operations (my app will download podcast files). So, I have a PodcastManager class with this method, where I use a Podcast object created by me too: ``` - (void)downloadPodcast:(Podcast *)podcast completion:(CompletionBlock)completionBlock{ podcast.downloadState = DOWNLOADING; NSURL *url = [NSURL URLWithString:podcast.enclosure]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; NSProgress *progress = [NSProgress progressWithTotalUnitCount:podcast.size]; NSURLSessionDownloadTask *downloadTask = [self.downloadManager downloadTaskWithRequest:request progress:&progress destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) { NSURL *documentsDirectoryPath = [NSURL fileURLWithPath:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]]; //Return final path for podcast file } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) { if (!error) { //Handle success } else{ //Handle errors } }]; [progress addObserver:self forKeyPath:@"fractionCompleted" options:NSKeyValueObservingOptionNew context:nil]; [downloadTask resume]; if (completionBlock) { dispatch_async(dispatch_get_main_queue(), ^{ completionBlock(); }); } } ``` Right now, for debugging purposes I have this also in `PodcastManager`: ``` - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"fractionCompleted"] && [object isKindOfClass:[NSProgress class]]) { NSProgress *progress = (NSProgress *)object; NSLog(@"Download at %f", progress.fractionCompleted); } } ``` I call the downloadPodcast:completion: method from a UITableViewController, where every cell represents a Podcast. What I'm trying to do is show a custom Progress View in the cell with the progress of the download of that podcast. I know that AFNetworking 2.0 has a great UIProgressView that gets progress of a download task easily, but in my app I'm using this custom progress view https://github.com/danielamitay/DACircularProgress so I can't use this feature :( Anyone can show me the way to do this right? Thanks UPDATE: Well, I made some progress with this problem. Now I can access to the progress of the download from my custom cell using KVO. Using the method from AFURLSessionManager setDownloadTaskDidWriteDataBlock I get the current percentage of the download, and I save it in a property of the cell. ``` [[manager downloadManager] setDownloadTaskDidWriteDataBlock:^(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) { self.downloadPercentage = (float)totalBytesWritten/(float)totalBytesExpectedToWrite; }]; ``` Then with KVO i look over my property ``` - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"downloadPercentage"] && [object isKindOfClass:[FDSEpisodeCell class]]) { int percentage = self.downloadPercentage * 100; NSLog(@"Percentage %d", percentage); [self.downloadLabel setText:[NSString stringWithFormat:@"%d",percentage]]; } } ``` My problem now is that I'm trying to show this percentage in a UILabel inside the cell, but although I change the label text, nothing changes. How can I refresh the label to show the current percentage?. I tried to use setNeedsDisplay but nothing happened. And if I use reloadData from the TableView, something weird happens and the view turns into blank. Also, i tried with a NSTimer, but neither worked.