UITableView при прокрутке вверх

Решение: используйте SDWebImage: https://github.com/rs/SDWebImage

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

Я использую пользовательский UITableViewCell. Это также причина, по которой она отстает?

Мой пользовательский UITableViewCell:

enter image description here

Мой код:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

NSString *CellIdentifier = [NSString stringWithFormat:@"Cell%d%d",indexPath.row,indexPath.section];


tableViewCellActiviteiten *cell = (tableViewCellActiviteiten *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil)
{

    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"tableViewCellActiviteiten" owner:self options:nil];
    cell = (tableViewCellActiviteiten *)[nib objectAtIndex:0];
}


cell.thetitle.text = [self.alletitels objectAtIndex:indexPath.row];
cell.thesubtitle.text = [self.allesubtitels objectAtIndex:indexPath.row];

NSString * imagePath = [self.alleimages objectAtIndex:indexPath.row];

NSURL * imageURL = [NSURL URLWithString:imagePath];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * image = [UIImage imageWithData:imageData];

cell.image.image = image;

return cell;

}

Содержимое массивов:

self.alletitels содержит строку: "Title Activity"

self.allesubtitels содержит строку: "Субтитр активности"

self.alleimages содержит URL: " http://m2.myhappygames.com//files/pics/0/Paranormal_Shark_Activity_3.jpg"

Может ли кто-нибудь посоветовать, что может быть причиной медленной прокрутки?

Ответы

Ответ 1

Проблема заключается в том, что каждый раз, когда метод tableView: cellForRowAtIndexPath: называется вашим кодом, создается изображение. Это будет вызываться каждый раз, когда ячейка появляется на экране, поэтому, если вы прокрутите очень быстро, этот метод начнет выделять много изображений синхронно, что замедлит прокрутку.

Как быстрое решение, внедрите NSCache в свой контроллер просмотра и сохраните в нем изображения.

UIImage *image = [_imageCache objectForKey:@indexPath.row];
if (image == nil) {
    NSString * imagePath = [self.alleimages objectAtIndex:indexPath.row];
    NSURL * imageURL = [NSURL URLWithString:imagePath];
    NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
    image = [UIImage imageWithData:imageData];
    [_imageCache setObject:image forKey:@indexPath.row];
}

cell.image.image = image;

_imageCahce - это переменная экземпляра контроллера вида, которую вы можете реализовать.

Надеюсь, это поможет, ура!

Ответ 2

Эти две строки:

NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * image = [UIImage imageWithData:imageData];

Значительно замедляет производительность вашей таблицы.

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

Было бы разумнее кэшировать (или сохранять локально) изображения, которые будут отображаться. И если они не сохраняются локально или в кеше, только затем зайдите в эти изображения (и сделайте это асинхронно, вне этого метода cellForRowAtIndexPath:).

Ответ 3

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

Решением для этого является использование техники, называемой "ленивая загрузка". В этом методе загрузка изображения будет происходить на отдельном потоке, тем самым разблокируя основной поток. Изображение загружается, а затем применяется к правильному контейнеру UIImageView. Здесь Пример кода Apple для ленивой загрузки изображений в виде таблицы.

Вы также можете использовать SDWebImage. Это также сделает кэширование изображений.

#import <SDWebImage/UIImageView+WebCache.h>

...

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

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];

    if (cell == nil)
    {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                       reuseIdentifier:MyIdentifier] autorelease];
    }

    // Here we use the new provided setImageWithURL: method to load the web image
    [cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
                   placeholderImage:[UIImage imageNamed:@"placeholder.png"]];

    return cell;
}

Надеюсь, что это поможет!

Ответ 4

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

// get a data provider referencing the relevant file
CGDataProviderRef dataProvider = CGDataProviderCreateWithFilename(filename);

// use the data provider to get a CGImage; release the data provider
CGImageRef image = CGImageCreateWithPNGDataProvider(dataProvider, NULL, NO, 
                                                kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);

// make a bitmap context of a suitable size to draw to, forcing decode
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
unsigned char *imageBuffer = (unsigned char *)malloc(width*height*4);

CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();

CGContextRef imageContext =
CGBitmapContextCreate(imageBuffer, width, height, 8, width*4, colourSpace,
              kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);

CGColorSpaceRelease(colourSpace);

// draw the image to the context, release it
CGContextDrawImage(imageContext, CGRectMake(0, 0, width, height), image);
CGImageRelease(image);

// now get an image ref from the context
CGImageRef outputImage = CGBitmapContextCreateImage(imageContext);

// post that off to the main thread, where you might do something like
// [UIImage imageWithCGImage:outputImage]
[self performSelectorOnMainThread:@selector(haveThisImage:) 
     withObject:[NSValue valueWithPointer:outputImage] waitUntilDone:YES];

// clean up
CGImageRelease(outputImage);
CGContextRelease(imageContext);
free(imageBuffer);

Вы также можете использовать UIImage + ImmediateLoad.m Он немедленно декодирует изображения. Помимо UIImage -initWithContentsOfFile:, -imageWithCGImage: и CG * являются потокобезопасными после iOS4.

Ответ 5

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

Ответ 6

У меня была аналогичная проблема, я изучил ее с помощью Profiler, так что вот несколько примеров:

1) Вы используете неправильный идентификатор повторного использования, вы всегда должны использовать один и тот же идентификатор.

вместо этого:

NSString *CellIdentifier = [NSString stringWithFormat:@"Cell%d%d",indexPath.row,indexPath.section];

используйте это:

NSString *CellIdentifier = @"MyIdentifier";

для более подробной информации: как использовать UItableViewCell reuseIdentifier

2) loadNibNamed метод очень медленный (плюс вы каждый раз загружаете его каждую ячейку), вы должны избавиться от nib и поместить элементы пользовательского интерфейса из кода, перезаписав этот метод UITableViewCell

-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier;

3) используйте Instruments

Ответ 7

Вы делаете синхронный сетевой вызов для каждого изображения. То, что вы получаете лаг в своем приложении. Попробуйте AsyncImageView  он будет загружать ваши изображения из сети асинхронно. И вы сможете удалить отставание от своего приложения.: -)