Apple say not to subclass UIImageView, according to the UIImageView class reference. Thank you to @rob mayoff for pointing this out.
However, if you're implementing your own drawRect, start with your own UIView subclass. And, it's within drawRect that you use addClip. You can do this with a UIBezierPath without converting it to a CGPath.
- (void)drawRect:(CGRect)rect
{
// This assumes the clippingPath and image may be drawn in the current coordinate space.
[[self clippingPath] addClip];
[[self image] drawAtPoint:CGPointZero];
}
If you want to scale up or down to fill the bounds, you need to scale the graphics context. (You could also apply a CGAffineTransform to the clippingPath, but that is permanent, so you'd need to copy the clippingPath first.)
- (void)drawRect:(CGRect)rect
{
// This assumes the clippingPath and image are in the same coordinate space, and scales both to fill the view bounds.
if ([self image])
{
CGSize imageSize = [[self image] size];
CGRect bounds = [self bounds];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextScaleCTM(context, bounds.size.width/imageSize.width, bounds.size.height/imageSize.height);
[[self clippingPath] addClip];
[[self image] drawAtPoint:CGPointZero];
}
}
This will scale the image separately on each axis. If you want to preserve its aspect ratio, you'll need to work out the overall scaling, and possibly translate it so it's centered or otherwise aligned.
Finally, all of this is relatively slow if your path gets drawn a lot. You will probably find it's faster to store the image in a CALayer, and mask that with a CAShapeLayer containing the path. Do not use the following methods except for testing. You will need to separately scale the image layer and the mask to make them line up. The advantage is that you can change the mask without the underlying image being rendered.
- (void) setImage:(UIImage *)image;
{
// This method should also store the image for later retrieval.
// Putting an image directly into a CALayer will stretch the image to fill the layer.
[[self layer] setContents:(id) [image CGImage]];
}
- (void) setClippingPath:(UIBezierPath *)clippingPath;
{
// This method should also store the clippingPath for later retrieval.
if (![[self layer] mask])
[[self layer] setMask:[CAShapeLayer layer]];
[(CAShapeLayer*) [[self layer] mask] setPath:[clippingPath CGPath]];
}
If you do make image clipping with layer masks work, you no longer need a drawRect method. Remove it for efficiency.