Improving Scrolling Performance of Circles on iOS

Hint: Don’t use view.layer.cornerRadius.

Circular avatars are all the rage lately, with even Apple adopting them for contacts in iOS 7.

There’s a very easy way to make a circle from a UIImageView (and in fact, any UIView).

// ...
    [self.imageView setImage:user.avatarImage];
    [self.imageView.layer setCornerRadius:view.frame.size.width/2];
// ...

However, this is very slow if you’re planning to use it for something like a list of avatars in a UITableView. You’ll notice jittering/stuttering even on an iPhone 5.

A much faster way is by masking the image.

// ...
    [imageView setImage:[self maskedAvatarFromImage:user.avatarImage]];
// ...

- (UIImage *)maskedAvatarFromImage:(UIImage *)image {

    // set up the drawing context
    CGRect imageRect = CGRectMake(0, 0, image.size.width, image.size.height);
    UIGraphicsBeginImageContextWithOptions(imageRect.size, NO, 0);

    // set up a path to mask/clip to, and draw it.
    UIBezierPath *circlePath = [UIBezierPath bezierPathWithOvalInRect:imageRect];
    [circlePath addClip];
    [image drawInRect:imageRect];

    // get a UIImage from the image context
    UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return maskedImage;
}

You could also use an image asset as a mask, but I haven’t found that there’s a significant performance difference between the two.