Ser Pounce
Ser Pounce

Reputation: 14547

Stuttering when Drawing to Image in GCD Block

I have the following method which takes some CAShapeLayers and converts them into a UIImage. The UIImage is used in a cell for a UITableView (much like the photos app when you select a photo from one of your libraries). This method is called from within a GCD block:

-(UIImage*) imageAtIndex:(NSUInteger)index
{
    Graphic *graphic = [[Graphic graphicWithType:index]retain];

    CALayer *layer = [[CALayer alloc] init];
    layer.bounds = CGRectMake(0,0, graphic.size.width, graphic.size.height);
    layer.shouldRasterize = YES;
    layer.anchorPoint = CGPointZero;
    layer.position = CGPointMake(0, 0);

    for (int i = 0; i < [graphic.shapeLayers count]; i++)
    {
        [layer addSublayer:[graphic.shapeLayers objectAtIndex:i]];
    }

    CGFloat largestDimension = MAX(graphic.size.width, graphic.size.height);
    CGFloat maxDimension = self.thumbnailDimension;
    CGFloat multiplicationFactor = maxDimension / largestDimension;
    CGSize graphicThumbnailSize = CGSizeMake(multiplicationFactor * graphic.size.width, multiplicationFactor * graphic.size.height);

    layer.sublayerTransform = CATransform3DScale(layer.sublayerTransform, graphicThumbnailSize.width / graphic.size.width, graphicThumbnailSize.height / graphic.size.height, 1);
    layer.bounds = CGRectMake(0,0, graphicThumbnailSize.width, graphicThumbnailSize.height);

    UIGraphicsBeginImageContextWithOptions(layer.bounds.size, NO, 0);
    [layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = [UIGraphicsGetImageFromCurrentImageContext() retain];
    UIGraphicsEndImageContext();

    [layer release];
    [graphic release];

    return [image autorelease];
}

For whatever reason, when I'm scrolling the UITableView and loading the images in, it is stuttering a little bit. I know the GCD code is fine because it's worked previously so it appears something in this code is causing the stuttering. Does anyone know what that could be? Is CAAnimation not thread safe? Or does anyone know a better way to take a bunch of CAShapeLayers and convert them into a UIImage?

Upvotes: 1

Views: 193

Answers (1)

Ser Pounce
Ser Pounce

Reputation: 14547

In the end I believe:

[layer renderInContext:UIGraphicsGetCurrentContext()];

Cannot be done on a separate thread, so I had to do the following:

UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
//draw the mutable paths of the CAShapeLayers to the context
UIImage *image = [UIGraphicsGetImageFromCurrentImageContext() retain];
UIGraphicsEndImageContext(); 

There is a great example of this (where I learned to do it) in the WWDC2012 video "Building Concurrent User Interfaces on iOS"

Upvotes: 1

Related Questions