Pangu
Pangu

Reputation: 3819

UICollectionView initial scroll lag?

I have set up a 3x18 "grid view" using the UICollectionView class. Each cell contains a UIImageView that is loaded from an NSDictionary. There are 18 images, totaling around "20 MB".

The problem I have is when I'm initially in the view, and I scroll from the top to the bottom, it's laggy. After that, the scrolling is as smooth as the Photos app.

Why is that the case? Is it because my images are too big?

Here is my code:

- (void)viewDidLoad

{
    [super viewDidLoad];

    dictionary = @{@"01"    : @[@"Image 1"],
                   @"02"    : @[@"Image 2"],
                   // etc etc 
                  };

    numOfImages = [ [dictionary allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];

    // Allows appropriate methods to be used
    self.pageantCollectionView.delegate = self;
    self.pageantCollectionView.dataSource = self;
}

// Populate each cell with specified data

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

{
    CustomCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];

    NSString *number = [numOfImages objectAtIndex:indexPath.row];

    NSArray *imageByNumber = [dictionary objectForKey:number];

    NSString *name= [imageByNumber objectAtIndex:indexPath.section];

    cell.nameLabel.text = name;

    cell.imageView.image = [UIImage imageNamed:[self getImage:name] ];

    // Set rounded corners
    CALayer * l = [cell.imageView layer];

    [l setMasksToBounds:YES];

    [l setCornerRadius:10.0];

    return cell;
}

- (void)collectionView:(UICollectionView *)colView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath {

    UICollectionViewCell* cell = [colView cellForItemAtIndexPath:indexPath];

    CALayer * l = [cell layer];

    [l setMasksToBounds:YES];

    [l setCornerRadius:10.0];

    cell.contentView.backgroundColor = [UIColor lightGrayColor];

}

- (void)collectionView:(UICollectionView *)colView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath 
{
    UICollectionViewCell* cell = [colView cellForItemAtIndexPath:indexPath];
    cell.contentView.backgroundColor = nil;    
}

Does it have anything to do with the fact that I'm setting the corner radius for the "imageView" dynamically within cellForItemAtIndexPath, and also the corner radius for the cell itself within didHighlightItemAtIndexPath?

If that is the case, how can I go about statically creating the corner radius for the "imageView" and "cell" itself?

Thanks

Upvotes: 3

Views: 2657

Answers (2)

Daniel Shaffer
Daniel Shaffer

Reputation: 51

Create a custom UICollectionViewCell, and in the subclass of your cell in the awakeFromNib method, set the corner radius and anything else. This is to prevent it from modifying the layer EVERY time (as it currently does via the cellForItem method).

i.e.:

CustomCell *cell = (CustomCell*)[colView cellForItemAtIndexPath:indexPath];

Also make sure to register the cell in viewDidLoad (you can find custom cell guides all over).

Upvotes: 2

foundry
foundry

Reputation: 31745

The delay is more likely to be the image loading using [UIImage imageNamed:] First time round, these are loaded from disk (slow). Subsequently they will be loaded from the memory cache, which will be fast. You will get a worse result, the larger your images.

Things to consider

  • How large are you images (in pixel dimensions) compared with their view size? If they are substantially larger, you should consider providing thumbnail versions at the display size.

  • Preloading. Is there a better place in the app to incur this delay? Such as during startup (before the collectionView is displayed? If so try loading them all (using imageNamed:) into an NSDictionary or an NSCache (that's like a dictionary that gets flushed out in low memory conditions)

  • Asynchronous loading. Consider using UIImage imageFromContentsOfFile: instead, which you can put in a background thread (then load the image into the imageView on the main thread). Unlike imageNamed this method does not cache, but you can do that manually by adding the result to an NSCache. You will need to write a bit of code to favour getting the image from the cache when available in preference to refetching it from disk.
    You might be OK doing this with imageNamed - but it is not thread-safe so you shouldn't really attempt it (see the comments alongside this answer).

  • possibly forcing an initial offscreen draw on a background thread before displaying the image on the main thread. This forces the image to decompress in the background. You would need to experiment with this technique in conjunction with the previous one to see if it really makes a difference for you.

  • Cell initialisation. Anything that only needs to happen once to a cell, shouldn't be done in cellForItem.... You could move these things (such as your cell layer corner radius) into a cell init method, as Daniel Shaffer suggests. You should do this anyway, although I don't think this will be the main reason for your current scrolling woes.

Upvotes: 3

Related Questions