4

I decided to draw my UICollectionViewCell's with drawRect: instead of the custom xib files for performance (as I have shadows and label shadows).

For some reason, since I changed this, my cells not draw with different images each time they are reloaded into the UICollectionView.

When I log the name of the image it is set to load in both the collectionView:cellForItemAtIndexPath and drawRect: it supplies the correct name of the image and the correct index path, yet when I load the app, it muddles them up on scrolling, even though initially, they have loaded correctly.

Here is my code:

viewDidLoad

//  Collection cells
//
[self.collectionView registerClass:[CluelessSymbolCell class] forCellWithReuseIdentifier:@"Symbol cell"];

collectionView:cellForItemAtIndexPath

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    CluelessSymbolCell *cell = (CluelessSymbolCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"Symbol cell" forIndexPath:indexPath];

    CluelessClue *clue = [self.clues objectAtIndex:indexPath.row];

    NSLog(@"(%@) Image: %@", indexPath, [clue.imageNames objectAtIndex:0]);

    [cell setClue:clue];

    return cell;
}

drawRect: (In cell subclass 'CluelessSymbolCell')

- (void)drawRect:(CGRect)rect
{
    NSString *imageName = [NSString stringWithFormat:@"%@-icon-iphone", [self.clue.imageNames objectAtIndex:0]];

    //  Cell
    //
    [self.contentView.layer setShadowColor:[UIColor blackColor].CGColor];
    [self.contentView.layer setShadowOpacity:0.3f];
    [self.contentView.layer setShadowRadius:2.0f];
    [self.contentView.layer setShadowOffset:CGSizeZero];
    [self.contentView.layer setShadowPath:[UIBezierPath bezierPathWithRect:self.layer.bounds].CGPath];

    //      Image
    //
    CALayer *imageLayer = [CALayer layer];
    [imageLayer setFrame:rect];
    [imageLayer setContents:(id)[[UIImage imageNamed:imageName] CGImage]];

    [self.contentView.layer addSublayer:imageLayer];
}

Edit

On logging the sublayers of the cell's content view, I can see that each cell's contentview sublayer has moved to the next cell, what is the reason for this and how do I overcome it?

Log:

2013-02-22 23:41:08.064 Clueless[3462:c07] <NSIndexPath 0x845cb90> 2 indexes [0, 0], (null)
2013-02-22 23:41:08.065 Clueless[3462:c07] <NSIndexPath 0x84435f0> 2 indexes [0, 1], (null)
2013-02-22 23:41:08.066 Clueless[3462:c07] <NSIndexPath 0x8446f50> 2 indexes [0, 2], (null)
2013-02-22 23:41:08.066 Clueless[3462:c07] <NSIndexPath 0x843a060> 2 indexes [0, 3], (null)
2013-02-22 23:41:08.067 Clueless[3462:c07] <NSIndexPath 0x846bc70> 2 indexes [0, 4], (null)
2013-02-22 23:41:08.067 Clueless[3462:c07] <NSIndexPath 0x845cd20> 2 indexes [0, 5], (null)
2013-02-22 23:41:08.068 Clueless[3462:c07] <NSIndexPath 0x845ce60> 2 indexes [0, 6], (null)
2013-02-22 23:41:08.068 Clueless[3462:c07] <NSIndexPath 0x846ce40> 2 indexes [0, 7], (null)
2013-02-22 23:41:08.069 Clueless[3462:c07] <NSIndexPath 0x846c9b0> 2 indexes [0, 8], (null)
2013-02-22 23:41:08.069 Clueless[3462:c07] <NSIndexPath 0x846d880> 2 indexes [0, 9], (null)
2013-02-22 23:41:08.070 Clueless[3462:c07] <NSIndexPath 0x846db20> 2 indexes [0, 10], (null)
2013-02-22 23:41:08.071 Clueless[3462:c07] <NSIndexPath 0x846df30> 2 indexes [0, 11], (null)
2013-02-22 23:41:15.105 Clueless[3462:c07] <NSIndexPath 0x846ec60> 2 indexes [0, 12], (null)
2013-02-22 23:41:15.106 Clueless[3462:c07] <NSIndexPath 0x846efb0> 2 indexes [0, 13], (null)
2013-02-22 23:41:15.107 Clueless[3462:c07] <NSIndexPath 0x846f6d0> 2 indexes [0, 14], (null)
2013-02-22 23:41:15.753 Clueless[3462:c07] <NSIndexPath 0x82492e0> 2 indexes [0, 15], (
    "<CALayer: 0x8495840>"
)
2013-02-22 23:41:15.754 Clueless[3462:c07] <NSIndexPath 0x827f750> 2 indexes [0, 16], (
    "<CALayer: 0x8491010>"
)
2013-02-22 23:41:15.754 Clueless[3462:c07] <NSIndexPath 0x827f5c0> 2 indexes [0, 17], (
    "<CALayer: 0x8493ef0>"
)
2013-02-22 23:41:15.986 Clueless[3462:c07] <NSIndexPath 0x845cb90> 2 indexes [0, 0], (
    "<CALayer: 0x8493ef0>"
)
2013-02-22 23:41:15.987 Clueless[3462:c07] <NSIndexPath 0x84435f0> 2 indexes [0, 1], (
    "<CALayer: 0x8491010>"
)
2013-02-22 23:41:15.987 Clueless[3462:c07] <NSIndexPath 0x8446f50> 2 indexes [0, 2], (
    "<CALayer: 0x8495840>"
)
2013-02-22 23:41:26.161 Clueless[3462:c07] <NSIndexPath 0x827d970> 2 indexes [0, 12], (
    "<CALayer: 0x8241e20>"
)
2013-02-22 23:41:26.162 Clueless[3462:c07] <NSIndexPath 0x824e9d0> 2 indexes [0, 13], (
    "<CALayer: 0x827bc60>"
)
2013-02-22 23:41:26.163 Clueless[3462:c07] <NSIndexPath 0x827d030> 2 indexes [0, 14], (
    "<CALayer: 0x8242fb0>"
)
2013-02-22 23:41:26.776 Clueless[3462:c07] <NSIndexPath 0x82492e0> 2 indexes [0, 15], (
    "<CALayer: 0x8491010>"
)
2013-02-22 23:41:26.777 Clueless[3462:c07] <NSIndexPath 0x827f750> 2 indexes [0, 16], (
    "<CALayer: 0x8493ef0>"
)
2013-02-22 23:41:26.778 Clueless[3462:c07] <NSIndexPath 0x827f5c0> 2 indexes [0, 17], (
    "<CALayer: 0x8495840>"
)
2013-02-22 23:41:26.926 Clueless[3462:c07] <NSIndexPath 0x845cb90> 2 indexes [0, 0], (
    "<CALayer: 0x8495840>"
)
2013-02-22 23:41:26.927 Clueless[3462:c07] <NSIndexPath 0x84435f0> 2 indexes [0, 1], (
    "<CALayer: 0x8493ef0>"
)
2013-02-22 23:41:26.928 Clueless[3462:c07] <NSIndexPath 0x8446f50> 2 indexes [0, 2], (
    "<CALayer: 0x8491010>"
)
Adam Carter
  • 4,741
  • 5
  • 42
  • 103
  • Each row has three columns, and if I refresh just one row, a cell's image will move to the next index in the row, then the last, then back to the first... – Adam Carter Feb 22 '13 at 22:44
  • This happens because the collectionview reuses the cells without having to redraw them. – atreat May 22 '13 at 22:41

1 Answers1

1

I don't know if it's a bug, or some kind of problem my end.

However, it seems that to overcome this you need to force drawRect: inside prepareForReuse

- (void)prepareForReuse
{
    [super prepareForReuse];

    [self setNeedsDisplay];
}
Adam Carter
  • 4,741
  • 5
  • 42
  • 103
  • You shouldn't fetch the image in drawRect. Your CollectionViewCell should keep an ivar that holds the image and your drawrect should draw this image. In your prepareForReuse method you can set the image ivar to nil. Then your data source should set the image or image name in cellAtIndexPath:. – atreat May 22 '13 at 22:40
  • you must not add layers in drawRect either... its very heavy operation. drawRect is called everytime cell needs to draw itself (user tap on cell , resize, rotations, etc...) you keep adding layers every-time there is requirement for redrawing. a suggestion is to use the hosted layer of the cell itself to set the image. – nsuinteger Oct 31 '13 at 02:53