【问题标题】:Getting Download progress with AFNetworking 2.0 + NSProgress + Custom ProgressView使用 AFNetworking 2.0 + NSProgress + 自定义 ProgressView 获取下载进度
【发布时间】:2023-03-13 23:13:01
【问题描述】:

我在尝试使用 AFNetworking 2.0 从下载任务中获取进度时感到困惑。我创建了一个单例对象,在其中集中了我的下载操作(我的应用程序将下载播客文件)。

所以,我有一个带有此方法的 PodcastManager 类,其中我也使用了我创建的 Podcast 对象:

- (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();
   });
 } 
}

现在,出于调试目的,我在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);
  }
}

我从 UITableViewController 调用 downloadPodcast:completion: 方法,其中每个单元格代表一个 Podcast。我要做的是在单元格中显示一个自定义进度视图,其中包含该播客的下载进度。

我知道 AFNetworking 2.0 有一个很棒的 UIProgressView 可以轻松获取下载任务的进度,但在我的应用程序中我使用的是这个自定义进度视图https://github.com/danielamitay/DACircularProgress 所以我不能使用这个功能:(

任何人都可以告诉我如何做到这一点吗? 谢谢

更新:好吧,我在这个问题上取得了一些进展。现在我可以使用 KVO 从我的自定义单元中访问下载进度。使用 AFURLSessionManager setDownloadTaskDidWriteDataBlock 中的方法,我得到了当前的下载百分比,并将其保存在单元格的属性中。

[[manager downloadManager] setDownloadTaskDidWriteDataBlock:^(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {

  self.downloadPercentage = (float)totalBytesWritten/(float)totalBytesExpectedToWrite;
}];

然后我用 KVO 查看我的财产

- (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]];

 }
}

我现在的问题是我试图在单元格内的 UILabel 中显示这个百分比,但是虽然我更改了标签文本,但没有任何变化。如何刷新标签以显示当前百分比?我尝试使用 setNeedsDisplay 但什么也没发生。如果我使用 TableView 中的 reloadData,就会发生一些奇怪的事情,并且视图会变成空白。

另外,我尝试使用 NSTimer,但都没有成功。

【问题讨论】:

  • 如何将downloadTask... 创建的NSProgress 对象交给UITableViewCell 的子类并让它监听fractionComplete 并更新进度视图...
  • 运行时如何访问downloadTask的NSProgress对象?我必须将它保存在某个对象属性中还是有其他方式?
  • downloadTaskWithRequest... 方法将一个新的NSProgress 对象分配给您的进度指针。为什么不从你的方法中返回呢?
  • 我认为那样我们会有一些问题。我的 downloadPodcast:completion: 方法不是从单元格中调用的,所以我不能以这种方式返回 NSProgress 对象。如果将其保存在属性中,我可以访问它,但我仍然必须使用 KVO 来监视 fractionComplete,对吧?

标签: ios iphone objective-c ios7 afnetworking-2


【解决方案1】:

使用 AFURLConnectionOperation -setDownloadProgressBlock:,每次调用块时以 totalBytesRead 与 totalBytesExpectedToRead 的比率更新进度。

要更新您的 UI 元素,只需通过主线程调用更新:

dispatch_async(dispatch_get_main_queue(), ^(void){
    //Run UI Updates
});

【讨论】:

  • 成功了! :D 非常感谢
【解决方案2】:

Swift 的简单解决方案:

let progressView: UIProgressView?
let sessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
let sessionManager = AFURLSessionManager(sessionConfiguration: sessionConfiguration)
let request = NSURLRequest(URL: url)
let sessionDownloadTask = sessionManager.downloadTaskWithRequest(request, progress: nil, destination: { (url, response) -> NSURL in

            return destinationPath.URLByAppendingPathComponent(fileName) //this is destinationPath for downloaded file

            }, completionHandler: { response, url, error in

                //do sth when it finishes
        })

使用UIProgressViewsetProgressWithDownloadProgressOfTask:

progressView.setProgressWithDownloadProgressOfTask(sessionDownloadTask, animated: true)

sessionDownloadTask.resume()

【讨论】:

    猜你喜欢
    • 2013-10-09
    • 1970-01-01
    • 1970-01-01
    • 2016-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多