#objective-c #asynchronous #uitableview #nsurlconnection #nsurlrequest
#objective-c #асинхронный #uitableview #nsurlconnection #nsurlrequest
Вопрос:
Я пытаюсь асинхронно загружать изображения для 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:@"amp;quot;" withString:@"""] stringByReplacingOccurrencesOfString:@"amp;<" withString:@"<"] stringByReplacingOccurrencesOfString:@"amp;>" 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];
}
Ответ №1:
Вы добавляете данные из каждого загруженного изображения в один и тот же объект данных. Таким образом, в лучшем случае объект данных заканчивается данными для изображения # 1, за которыми сразу следуют данные для изображения # 2 и так далее; декодер изображения, по-видимому, берет первое изображение в блоке данных и игнорирует мусор после. Вы также, похоже, не знаете, что NSURLConnections’ connection:didReceiveData:
не обязательно будет вызываться в том порядке, в котором были запущены соединения, это connection:didReceiveData:
может быть вызвано ноль или несколько раз для каждого соединения (и, вероятно, будет, если ваши изображения занимают более нескольких кибибайт), и это tableView:cellForRowAtIndexPath:
не гарантируется для вызова каждой ячейки в таблице по порядку. Все это собирается полностью испортить ваш _cellImages
массив.
Чтобы сделать это правильно, вам нужно иметь отдельный экземпляр NSMutableData для каждого соединения, и вам нужно добавить его в ваш _cellImages
массив только один раз, и с правильным индексом для строки, а не с произвольным следующим доступным индексом. И затем в connection:didReceiveData:
вам нужно определить правильный экземпляр NSMutableData для добавления; это может быть сделано с помощью объекта connection (завернутого в NSValue с использованием valueWithNonretainedObject:
) в качестве ключа в NSMutableDictionary, или с помощью objc_setAssociatedObject
прикрепления объекта data к объекту connection, или путем создания собственного класса, который обрабатывает все управление NSURLConnection для вас и передает вам объект data после завершения.
Ответ №2:
Я не знаю, является ли это причиной проблемы или нет, но в вашем connection:didReceiveData:
методе вы просто добавляете данные изображения в массив; вы должны хранить данные изображения таким образом, чтобы вы могли связать их с ячейкой, в которой они должны отображаться. Одним из способов сделать это было бы использовать an, NSMutableArray
заполненный множеством [NSNull]
s, затем заменить null
значение на соответствующий индекс, когда соединение завершит загрузку.
Кроме того, вы добавляете _cellData
в _cellImages
массив, когда загрузка соединения не завершена, вы должны делать это только в connection:didFinishLoading
методе.