UITableViewCell 上的 UIProgressView

Posted

技术标签:

【中文标题】UITableViewCell 上的 UIProgressView【英文标题】:UIProgressView on UITableViewCell 【发布时间】:2015-03-23 01:59:29 【问题描述】:

我正在使用 AFNetworking 从我的服务器下载文件。它工作正常。但是我有一个问题:当我向上或向下滚动时,我的 ProgressView 更新了错误的单元格(UI,而不是数据)。这是我的代码:

我的手机:

AFHTTPRequestOperation *operation;
@property (weak, nonatomic) IBOutlet DACircularProgressView *daProgressView;


- (IBAction)pressDown:(id)sender 
AFAPIEngineer *apiEngineer = [[AFAPIEngineer alloc] initWithBaseURL:[NSURL URLWithString:AF_API_HOST]];
                operation = [apiEngineer downloadFile:(CustomObject*)object withCompleteBlock:^(id result) 
                    
                 errorBlock:^(NSError *error) 
                    
                ];
                
                __weak typeof(self) weakSelf = self;
                apiEngineer.afProgressBlock = ^(double progress, double byteRead, double totalByToRead) 
                    [weakSelf.daProgressView setProgress:progress animated:YES];                    
                ;


- (void)setDataForCell:(id)object
    

我的桌子:

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    
            CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:NSStringFromClass([CustomCell class])];
            cell.backgroundColor = [UIColor clearColor];
       
            CustomObject *aObject = [listObject objectAtIndex:indexPath.row];
            [cell setDataForCell: aObject];
            
            return cell;
        

我的下载助手:

- (AFDownloadRequestOperation*)downloadFile:(CustomObject*)aObject
                          withCompleteBlock:(AFResultCompleteBlock)completeBlock
                                 errorBlock:(AFResultErrorBlock)errorBlock
        
    NSString *link = URL;
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:link]];
  
    NSString *path = [NSString databasePathWithPathComponent:[NSString stringWithFormat:@"%@.zip", @"noname"]];
    AFDownloadRequestOperation *operation = [[AFDownloadRequestOperation alloc] initWithRequest:request targetPath:path shouldResume:YES];
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) 
        completeBlock(responseObject);
     failure:^(AFHTTPRequestOperation *operation, NSError *error) 
        errorBlock(error);
    ];
    
    [operation setProgressiveDownloadProgressBlock:^(AFDownloadRequestOperation *operation, NSInteger bytesRead, long long totalBytesRead, long long totalBytesExpected, long long totalBytesReadForFile, long long totalBytesExpectedToReadForFile) 
        float progressF = (float)totalBytesReadForFile / totalBytesExpectedToReadForFile;
        self.afProgressBlock(progressF, totalBytesReadForFile, totalBytesExpectedToReadForFile);
    ];
    [operation start];
   
    return operation;

当我在第一个单元格中按下“下载”按钮时:

当我向下滚动然后向上滚动时,它是第二个单元格:

所以,我的问题是:如何在 UITableViewCell 上更新 UIProgressView?我的代码有什么问题?

【问题讨论】:

【参考方案1】:

由于单元格被重复使用,您根本不能只保留对单元格的弱引用并更新单元格的进度视图。至少,不要使用对表格视图单元格的弱引用,而是使用索引路径,使用 [tableView cellForRowAtIndexPath:indexPath] 查找正确的单元格(这是一个 UITableView 方法,用于标识与特定 @ 关联的单元格987654323@ 并且不应与名称相似的 UITableViewDataSource 方法混淆,我们在其中执行单元出列/配置逻辑),并更新该单元的进度视图(假设该单元甚至可见)。

坦率地说,即使这样也很危险,因为它假定在下载过程中不可能添加或删除单元格。 (这显然不是对应用程序的合理假设/约束。)坦率地说,每次想要更新下载进度时,真的应该回到模型,根据模型对象查找正确的NSIndexPath有问题,然后使用上面的cellForRowAtIndexPath 模式查找并更新有问题的单元格。

注意,这表明下载请求的发起可能不是由表格视图单元发起的。就我个人而言,我维护了一个模型对象,该对象由要下载的文件数组组成,并将下载队列与其关联,而不是单元格(尽管进度处理程序显然会更新单元格)。简而言之,您希望 UI(例如单元格)和驱动下载的模型之间存在松散耦合的关系。

请注意,许多幼稚的实现会考虑上述所有要点并决定放弃单元重用以简化问题。我不会详细说明这一点,但我认为这是一种从根本上被误导的方法。在我看来,应该有一个独立于视图对象的下载模型。

【讨论】:

感谢您的支持。【参考方案2】:

我在 github 上有一个小项目,基本上可以使用不同样式的进度指示器来满足您的需求。我不久前构建了它,它使用了 Rob 提到的方法:表格及其单元格由一个“模型”支持,该模型告诉给定 index 处的单元格它们的状态应该是什么。我还确保细胞被重复使用。它可能对你有用:

https://github.com/chefnobody/StreamingDownloadTest

【讨论】:

以上是关于UITableViewCell 上的 UIProgressView的主要内容,如果未能解决你的问题,请参考以下文章

UITableViewCell 上的动画

如何使 UITableViewCell 上的 UIProgressView 立即更改?

UITableViewCell 上的 UITextView

UITableViewCell 内的 UIView 上的 UIGestureRecognizer

UITableViewcell 和 UITableVIew 上的手势识别器

自定义 UITableViewCell:“loadNibNamed:”上的 SIGABRT