UIProgressView на UITableViewCell

Я использую AFNetworking для загрузки файлов с моего сервера. Работает нормально. Но у меня есть одна проблема: мой ProgressView обновляет неправильную ячейку (пользовательский интерфейс, а не данные) при прокрутке вверх или вниз. Вот мой код:

Моя клетка:

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;

}

Мой downloadHelper:

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

Когда я нажимаю кнопку "Скачать" в первой ячейке:

Когда я прокручиваю вниз, затем прокручиваю вверх, это вторая ячейка:

Итак, мой вопрос: как обновить UIProgressView на UITableViewCell? Что не так с моим кодом?

2 ответа

Поскольку ячейки используются повторно, вы просто не можете просто сохранить слабую ссылку на ячейку и обновить представление прогресса ячейки. По крайней мере, вместо того, чтобы использовать слабую ссылку на ячейку табличного представления, вы бы использовали путь индекса, ищите правильную ячейку, используя [tableView cellForRowAtIndexPath:indexPath] (это UITableView метод, который идентифицирует ячейку, связанную с конкретным NSIndexPath и не следует путать с одноименным UITableViewDataSource метод, в котором мы делаем логику удаления / конфигурирования нашей ячейки), и обновляем представление прогресса этой ячейки (предполагая, что ячейка даже видима).

Честно говоря, даже это опасно, так как предполагает, что невозможно добавлять или удалять ячейки во время загрузки. (И это явно не разумное предположение / ограничение для приложения.) Откровенно говоря, каждый раз, когда кто-то хочет обновить прогресс загрузки, нужно действительно вернуться к модели, найти правильный NSIndexPath на основе рассматриваемого модельного объекта, а затем используйте cellForRowAtIndexPath шаблон, чтобы найти, а затем обновить соответствующую ячейку.

Обратите внимание, что это предполагает, что инициирование запроса на загрузку может не инициироваться ячейкой табличного представления. Лично я поддерживаю объект модели, который состоит из массива файлов для загрузки, и связываю с ним очередь загрузки, а не ячейку (хотя обработчик прогресса, очевидно, обновит ячейку). Короче говоря, вам нужна слабосвязанная связь между пользовательским интерфейсом (например, ячейкой) и моделью, определяющей загрузку.

Обратите внимание, что многие наивные реализации учитывают все вышеперечисленные моменты и решают отказаться от повторного использования ячеек, чтобы упростить проблему. Я не буду вдаваться в подробности, но я думаю, что это принципиально ошибочный подход. На мой взгляд, нужно иметь подходящую модель для загрузки отдельно от объектов просмотра.

У меня есть небольшой проект на GitHub, который в основном делает то, что вы хотите с другим индикатором прогресса стиля. Я построил его некоторое время назад, и он использует именно тот подход, который упоминает Роб: таблица и ее ячейки опираются на "модель", которая сообщает ячейкам в заданном index каким должно быть их состояние. Я также уверен, что клетки используются повторно. Это может быть полезным для вас:

https://github.com/chefnobody/StreamingDownloadTest

Другие вопросы по тегам