Проблема с асинхронной загрузкой UITableView

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

Подскажите, пожалуйста, проблему с моим кодом:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
    }

    SearchObject *so = (SearchObject *)[_tableData objectAtIndex:indexPath.row];
    cell.textLabel.text = [[[[so tweet] stringByReplacingOccurrencesOfString:@"&quot;" withString:@"\""] stringByReplacingOccurrencesOfString:@"&lt;" withString:@"<"] stringByReplacingOccurrencesOfString:@"&gt;" withString:@">"];
    cell.detailTextLabel.text = [so fromUser];
    if (cell.imageView.image == nil) {
        NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:[so userProfileImageURL]]];
        NSURLConnection *conn = [NSURLConnection connectionWithRequest:req delegate:self];
        [conn start];
    }
    if ([_cellImages count] > indexPath.row) {
        cell.imageView.image = [UIImage imageWithData:[_cellImages objectAtIndex:indexPath.row]];
    }
    return cell;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [_cellData appendData:data];
    [_cellImages addObject:_cellData];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [self.tableView reloadData];
}

person max_    schedule 01.05.2011    source источник


Ответы (2)


Вы добавляете данные из каждого загруженного изображения в один и тот же объект данных. Таким образом, в лучшем случае объект данных заканчивается данными для изображения № 1, за которыми сразу же следуют данные для изображения № 2 и так далее; декодер изображений, по-видимому, берет первое изображение в блоке данных и игнорирует мусор после него. Вы также, кажется, не знаете, что connection:didReceiveData: NSURLConnections не обязательно будет вызываться в том порядке, в котором были запущены соединения, что connection:didReceiveData: может вызываться ноль или несколько раз за соединение (и, вероятно, будет, если ваши изображения больше, чем несколько кибибайт), и что tableView:cellForRowAtIndexPath: не гарантируется для каждой ячейки в таблице по порядку. Все это полностью испортит ваш массив _cellImages.

Чтобы сделать это правильно, вам нужно иметь отдельный экземпляр NSMutableData для каждого соединения, и вам нужно добавить его в свой массив _cellImages только один раз и по правильному индексу для строки, а не по произвольному следующему доступному индексу. А затем в connection:didReceiveData: вам нужно определить правильный экземпляр NSMutableData для добавления; это можно сделать, используя объект подключения (обернутый в NSValue с помощью valueWithNonretainedObject:) в качестве ключа в NSMutableDictionary, или используя objc_setAssociatedObject для присоединения объекта данных к объекту подключения, или создав себе класс, который обрабатывает все управление NSURLConnection для вас и передает вам объект данных по завершении.

person Anomie    schedule 02.05.2011

Я не знаю, вызывает ли это проблему или нет, но в вашем методе connection:didReceiveData: вы просто добавляете данные изображения в массив; вы должны хранить данные изображения таким образом, чтобы вы могли связать их с ячейкой, в которой они должны отображаться. Один из способов сделать это — использовать NSMutableArray, заполненный кучей [NSNull], а затем заменить значение null на соответствующий индекс, когда соединение закончило загрузку.

Кроме того, вы добавляете _cellData в массив _cellImages, когда соединение еще не закончило загрузку, вы должны делать это только в методе connection:didFinishLoading.

person conmulligan    schedule 02.05.2011