gpt4 book ai didi

ios - 如何取消 AFHTTPRequestOperation 并且不保留以前的进度

转载 作者:行者123 更新时间:2023-11-29 03:59:15 27 4
gpt4 key购买 nike

我有一个用于测试 AFNetworking 的应用程序API。它从服务器下载文档并将它们放置在应用程序的沙箱中。用户可以开始下载、暂停/恢复下载和取消下载。按预期启动、暂停和恢复所有工作。然而,取消做了一些我不期望的事情。

应用程序

表中的每个单元格代表一个“下载”,这是我的模型。表格 View Controller 监听单元格中的点击并将消息发送到 begin/cancel/pause/resume下载。我有课DownloadManager跟踪我的下载模型对象。我有三等AFFileDownloadAPIClient (使用 AFHTTPClient 作者推荐的 AFNetworking 模式)。 DownloadManagerAFFileDownloadAPIClient 上调用相应的消息进而调用 NSOperation 上的适当方法.

A simple AFNetworking download tracking app

代码

下面的方法创建一个新的AFHTTPRequestOperation ,将位流式传输到文件(这工作正常),并将其放入队列中,该队列为我启动操作。需要注意的几点: 1) 我在 "Content-Disposition" 中放入了一些元数据。像内容长度和生成的文件名这样的标题,因为下载开始时都不知道。请记住,这些位正在流式传输给我。 2) AFFileDownloadAPIClient保留一个带有整数索引键和 AFHTTPRequestOperation 的字典对于与 UITableView 中的索引对应的每个下载.我发现有必要稍后将操作检索到 pause , resume , 等等...

这是在 AFFileDownloadAPIClient :

- (void)downloadFileWithIndex:(int)index fileName:(NSString *)fileName {

// Using standard request operation
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];

operation.inputStream = [NSInputStream inputStreamWithURL:request.URL];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:fileInDocumentsPath append:YES];

// BLOCK level variables //
__weak AFHTTPRequestOperation *weakOperation = operation; // For use in download progress BLOCK
__weak NSDate *startTime = [NSDate date];

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

NSHTTPURLResponse *response = (NSHTTPURLResponse*)weakOperation.response;
NSString *contentDisposition = [[response allHeaderFields] objectForKey:@"Content-Disposition"];
NSArray *dispositionMetadata = [contentDisposition componentsSeparatedByString:@";"];

NSString *fileName = @"<?>";

// 3rd item is file name
if (dispositionMetadata != nil && dispositionMetadata.count == 4)
{
fileName = [dispositionMetadata objectAtIndex:2];
}

if ([_downloadFileRequestDelegate respondsToSelector:@selector(downloadFileRequestFinishedWithData:fileName:atIndex:startTime:)])
[_downloadFileRequestDelegate downloadFileRequestFinishedWithData:responseObject fileName:fileName atIndex:index startTime:startTime];

}

failure:^(AFHTTPRequestOperation *operation, NSError *error) {

if ([_downloadFileRequestDelegate respondsToSelector:@selector(downloadFileRequestFailedWithError:atIndex:startTime:)])
[_downloadFileRequestDelegate downloadFileRequestFailedWithError:error atIndex:index startTime:startTime];
}
];

// Check "Content-Disposition" for content-length
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {

NSHTTPURLResponse *response = (NSHTTPURLResponse*)weakOperation.response;
NSString *contentDisposition = [[response allHeaderFields] objectForKey:@"Content-Disposition"];
NSArray *dispositionMetadata = [contentDisposition componentsSeparatedByString:@";"];

// 4th item is length
if (dispositionMetadata != nil && dispositionMetadata.count == 4)
{
totalBytesExpectedToRead = [[dispositionMetadata objectAtIndex:3] doubleValue];
}

// Notify the delegate of the progress
if ([_requestProgressDelegate respondsToSelector:@selector(requestDidReceiveBytesForIndex:bytes:totalBytes:)])
[_requestProgressDelegate requestDidReceiveBytesForIndex:index bytes:bytesRead totalBytes:totalBytesExpectedToRead];
}];

// Check to see if operation is already in our dictionary
if ([[self.downloadOperations allKeys] containsObject:[NSNumber numberWithInt:index]] == YES)
[self.downloadOperations removeObjectForKey:[NSNumber numberWithInt:index]];

// Add operation to storage dictionary
[self.downloadOperations setObject:operation forKey:[NSNumber numberWithInt:index]];

// Queue up the download operation. No need to start the operation explicitly
[self enqueueHTTPRequestOperation:operation];

}

现在 cancel , pause , resume方法。请记住,暂停和恢复功能似乎工作得很好。
- (void)cancelDownloadForIndex:(int)index {

AFHTTPRequestOperation *operation = [self.downloadOperations objectForKey:[NSNumber numberWithInt:index]];

if (operation != nil) {

[operation cancel];

// Remove object from dictionary
[self.downloadOperations removeObjectForKey:[NSNumber numberWithInt:index]];
}
}

- (void)pauseDownloadForIndex:(int)index {

AFHTTPRequestOperation *operation = [self.downloadOperations objectForKey:[NSNumber numberWithInt:index]];

if (operation != nil)
[operation pause];
}

- (void)resumeDownloadForIndex:(int)index {

AFHTTPRequestOperation *operation = [self.downloadOperations objectForKey:[NSNumber numberWithInt:index]];

if (operation != nil)
[operation resume];
}

问题

假设我们要在中途取消下载。我会点击“开始”然后等待几秒钟。然后点击“X”取消。下面是之前/之后的图像。 (左边之前,右边之后)。

Before/after download and cancel operations

在您点击“X”后, View 会更改为显示原始的“GO”按钮,以便您可以重试,在这种情况下,我将其称为就绪状态(或“之前”)。我不明白的是,当我在刚刚取消的同一个下载中第二次点击“开始”时,我的进度指示器会在原来停止的 1.98 MB 的位置正确地拾取....好像取消没有'不要删除下载的原始字节,记住它们并从中断的地方继续。为什么?

Before/after download and cancel operations

问题
  • 为什么取消后的下载从中断的地方继续?
  • 这种行为是预期的还是意外的?

  • 对于这篇冗长的帖子,我深表歉意,并感谢您阅读本文。

    [编辑 1]

    为了更新 progressViewUITableViewCell我必须至少做这两件事。
  • 使用我称之为 Download 的数据模型类.
  • 使用管理我的模型的数据模型管理器类 Download对象及其状态。

  • 在表格 View Controller 中,我在给定索引处监听给定下载接收到的字节:
    - (void)downloadDidReceiveBytesForIndex:(int)downloadIndex bytes:(long long)bytes totalBytes:(double)totalBytes {

    NSIndexPath *path = [NSIndexPath indexPathForRow:downloadIndex inSection:0];

    DownloadTableViewCell *cell = (DownloadTableViewCell*)[self.tableView cellForRowAtIndexPath:path];

    Download *download = [_downloadManager.downloads objectAtIndex:path.row];
    download.bytesDownloaded += bytes;
    download.percentageDownloaded = download.bytesDownloaded / totalBytes;

    // as a factor of 0.0 to 1.0 not 100.
    cell.downloadProgressView.progress = download.percentageDownloaded;

    float MB_CONVERSION_FACTOR = 0.000000953674;

    NSString *bytesText = [NSString stringWithFormat:@"Downloading %.2f of %.2f MB", roundf((download.bytesDownloaded * MB_CONVERSION_FACTOR)*100)/100.0, roundf((totalBytes * MB_CONVERSION_FACTOR)*100)/100.0];

    cell.downloadProgressLabel.text = bytesText;
    }

    最后,为了处理滚动表和重用 UITableViewCell对象。我必须确保正确创建我的单元格,对应于正确的下载(在给定索引处)并反射(reflect)下载的确切状态。其中一些可能是矫枉过正,但它似乎运作良好。不过,我还没有在仪器中对此进行测试,以查看是否/何时泄漏任何东西:
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    static NSString *CellIdentifier = @"Cell";
    DownloadTableViewCell *cell = (DownloadTableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {

    UIViewController *temporaryController = [[UIViewController alloc] initWithNibName:@"DownloadTableViewCell" bundle:nil];
    // Grab a pointer to the custom cell.
    cell = (DownloadTableViewCell *)temporaryController.view;

    [cell initState];

    // Listens for method calls on cell
    cell.delegate = self;

    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    }

    // Set index for this cell (it could be wrong if cell is re-used)
    cell.downloadIndex = indexPath.row;

    Download *download = [_downloadManager.downloads objectAtIndex:indexPath.row];
    cell.downloading = download.downloading;

    cell.nameLabel.text = download.name;
    cell.descriptionLabel.text = download.description;
    cell.downloadProgressView.progress = download.percentageDownloaded;

    // Check for completed status
    cell.completed = download.completed;
    cell.completedFileNameLabel.text = download.fileName;

    return cell;
    }

    最佳答案

    在取消下载方法中从集合中删除时,似乎正在释放 outputStream。但是,由于下载被取消,下载实例上的状态不会发生变化。如果该对象继续具有 totalBytespercentageDownloaded值设置,进度 View 将继续反射(reflect)部分下载的状态。

    关于ios - 如何取消 AFHTTPRequestOperation 并且不保留以前的进度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16091091/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com