2012-05-10 2 views
0

Я загружаю асинхронные изображения в UITableView, и каждая строка имеет другое изображение. проблема, когда я прокрутки UITableView предыдущие изображения загружаются снова в новых строках и через некоторое время эти изображения меняются с правильными (эта проблема исчезает, когда я извлекал dequeueReusableCellWithIdentifier но это снижает производительность)UITableview dequeueReusableCellWithIdentifier и проблема UIImageView?

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{  
    static NSString *cellIdentifier = @"Cell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; 

    if(cell == nil) { 
     NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomCellFriends" owner:self options:nil]; 
     cell = [nibObjects objectAtIndex:0]; 
     nibObjects = nil; 
    } 

    UIImageView *avatar = (UIImageView *)[cell viewWithTag:100]; 
    UILabel *name = (UILabel *)[cell viewWithTag:2]; 
    UILabel *city = (UILabel *)[cell viewWithTag:3]; 

    EntryProfile *entryForRow = [entriesProfileArray objectAtIndex:indexPath.row]; 


    avatar.image = nil; 

    NSString *strLinkImage = [entryForRow.apiAvatarPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 
    NSArray *args = [NSArray arrayWithObjects:avatar,strLinkImage,[NSString stringWithFormat:@"%d",indexPath.row], nil]; 
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(addPhotoWithImageView:) object:args]; 
    [operationQueue addOperation:operation]; 
    [operation release]; 

    // Set the name of the user 
    name.text = entryForRow.name; 

    return cell; 
} 

// Method 
- (void)addPhotoWithImageView:(NSArray *)args 
{ 
    UIImageView *imageView = (UIImageView *)[args objectAtIndex:0]; 
    NSString *strLinkImage = (NSString *)[args objectAtIndex:1]; 
    NSString *index = (NSString *)[args objectAtIndex:2]; 

    NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://www.example.com%@",strLinkImage]]]; 
    UIImage *imageField = [[UIImage alloc] initWithData:imageData]; 

    if (imageData) { 
     [imageView performSelectorOnMainThread:@selector(setImage:) withObject:imageField waitUntilDone:NO]; 
    } 
    [imageField release]; 
} 

ответ

0

в cellForRowAtIndexPath, перед вызовом:

NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(addPhotoWithImageView:) object:args]; 

силы yourCell imageView.image к нулю

imageView.image = nil; 

таким образом вы очистите содержимое образа старой ячейки, то это будет перерисовывать с правом изображения, когда он загружен ...

EDIT

может быть ноль не работает ...

попробовать PlaceHolder образ, реальный PNG-файл (с цветом, для испытания, то он может быть прозрачным файлом ...)

+0

Я уже сделал это, но он не работает –

+0

Я вижу, что вы установили сверхурочное изображение cell.tag = 100, а не текущую ячейку ... почему? вам нужен какой-то специальный код, а не обычный режим UITableView? в этом случае объясните, каковы ваши потребности ... – meronix

+0

Это всего лишь тег, который относится к UIImageView –

0

пытаться реализовать свой собственный UITableViewCell и установить все свойства ячейки к нулю в метод PrepareForReuse.

Я также рекомендую вам взглянуть на этот проект для того, чтобы загрузить асинхронно удаленные изображения: https://github.com/nicklockwood/AsyncImageView

Я использовал его с большим успехом в различных проектах.

+0

Вы имеете в виду сделать цикл для каждого поднабора в UITableViewCell и установить их в nil? –

+0

Нет. Просто реализуйте свой собственный класс UItableViewCell вместо того, чтобы прямо создавать свой UItableViewCell из cellForRowAtIndexPath. Тогда реализовать PrepareForReuse – Charles

+0

я не понял, что вы имеете в виду? –

0

Если бы на днях подобный вопрос и как я решил, это было следующее (я не заметил снижения производительности).

 
UITableViewCell *cell; 

if (cell == nil) { 
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; 

// rest of the code 

} 

Так что в основном вызывать dequeue внутри if.

+0

Это на самом деле неправильно. Что делать, если нет повторно используемых ячеек для деактивации? Тогда ваша переменная 'cell' равна нулю. Исходный код плаката был правильным, по крайней мере, поскольку он относится к этому конкретному нюансу. –

+0

Знаешь что ... Я забираю его обратно. Это будет работать, если вы зарегистрируете класс для идентификатора повторного использования, вызвав 'registerNib: forCellReuseIndentifier:'. Но без этого, это само по себе не будет работать все время. –

3

Если есть люди, которые все еще сталкиваются с этой проблемой, я вижу, что ответы выше не помогают.

2 шага, чтобы взять с собой:

  • Вам нужно «отменить» асинхронный запрос, который продолжается для представления изображения, а затем установить новый образ асинхронно с заполнителем изображения до запроса асинхронной проходит через
  • В идеале не отправляйте свой асинхронный запрос во время прокрутки пользователя через (tableview/scrollview замедляется) - старайтесь избегать новых запросов и просто устанавливайте местозаполнитель в таких случаях (если у вас нет способа уверенно знать, что запрос было сделано до и, следовательно, вполне вероятно, что изображение найдено в кэш локального диска для URL-адреса изображения)

Вышеуказанные 2 шага будут поддерживать вашу функциональность по назначению и дать вам хорошую производительность.

+0

@meronix: установка элемента на нуль или на местозаполнитель может плохо работать в случае, если асинхронная загрузка была инициирована до того, как произойдет * после того, как * вы загрузите новый placeholder (может даже случиться, что новый запрос произойдет до старого, а затем см. неправильное изображение для ячейки). Нет гарантии того, когда запросы асинхронизации будут завершены и в каком порядке - так что единственный выход - отменить старые запросы. Проверьте AFNetworking за хорошую библиотеку, которая позволяет вам настроить изображение асинхронно с помощью заполнителя, а также отменить такие запросы (UIImage + AFNetworking.h) – Geebs

0

Это классическая проблема, легко решаемая.

В вашем cellForRowAtIndexPath: реализации, вы можете включить код, как это:

if (!tableView.decellerating) { 
    // set avatar.image to its correct UIImage value how ever you like, 
    // in the background if necessary 
} else { 
    // table is scrolling... 
    avatar.image = nil; 
} 

А затем реализовать этот метод в контроллере представления:

 
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 
{ 
    NSArray *visibleCells = [self.tableView visibleCells]; 
    [visibleCells enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 
     UITableViewCell *cell = (UITableViewCell *)obj; 
     UIImageView *avatar = (UIImageView *)[cell viewWithTag:100]; 
     avatar.image = ...; // Do what you need to do to set the image in the cell 
    }]; 
} 

Вам также нужно добавить UIScrollViewDelegate к списку протоколов, которые принимает ваш контроллер.

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

Смежные вопросы