3

I have subclassed a UILabel with the following code, which works fine - but any animations involving the subclass runs a lot slower than normal UILabels. I'm assuming Quartz is the culprit, but is there anything I could do to speed things up a bit?

- (void)drawTextInRect:(CGRect)rect
{
    CGSize shadowOffset = self.shadowOffset;
    UIColor *textColor = self.textColor;

    // Establish the Quartz 2D drawing destination:
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(context, 1);
    CGContextSetLineJoin(context, kCGLineJoinRound);

    // Draw the label’s outline:
    CGContextSetTextDrawingMode(context, kCGTextStroke);
    self.textColor = [UIColor whiteColor];
    [super drawTextInRect:rect];

    // Draw the label:
    CGContextSetTextDrawingMode(context, kCGTextFill);
    self.textColor = [UIColor textColor];
    self.shadowOffset = CGSizeMake(0, 0);
    [super drawTextInRect:rect];

    self.shadowOffset = shadowOffset;
}
achiral
  • 601
  • 2
  • 11
  • 24

2 Answers2

5

What @MobileOverlord said is certainly applicable, especially the parts about about profiling.

I will note that setting shouldRasterize=YES is not a catch-all solution (why wouldn't Apple have set it on as default if that were the case?). Yes, it can improve scrolling performance, but it can do so at the expense of memory use since you can end up with a bunch of large images sitting around in cache.

It also incurs overhead at the time of creation, I believe (but would have to check to be sure) including an off-screen rendering pass to actually create the rasterized copy. Depending on how the layer is used, this could actually hurt performance.

An additional factor to consider is whether your view has any transparency. If you can guarantee to the frameworks that your view is opaque (cf. setOpaque/isOpaque), they can optimize rendering by not considering all the complexities associated with alpha channels, etc. Similar considerations apply to CALayer.

Finally, outside the block of code you showed, did you do anything sneaky to the backing layer (e.g. set a shadow or corner radius)? That's a quick way to kill performance on animation too.

Conrad Shultz
  • 8,748
  • 2
  • 31
  • 33
3

After you are finished drawing your label you can call shouldRasterize on it's layer and it should speed up your animation.

shouldRasterize A Boolean that indicates whether the layer is rendered as a bitmap before compositing. Animatable

@property BOOL shouldRasterize Discussion When the value of this property is YES, the layer is rendered as a bitmap in its local coordinate space and then composited to the destination with any other content. Shadow effects and any filters in the filters property are rasterized and included in the bitmap. However, the current opacity of the layer is not rasterized. If the rasterized bitmap requires scaling during compositing, the filters in the minificationFilter and magnificationFilter properties are applied as needed.

When the value of this property is NO, the layer is composited directly into the destination whenever possible. The layer may still be rasterized prior to compositing if certain features of the compositing model (such as the inclusion of filters) require it.

The default value of this property is NO.

From CALayer Class Reference

The simulator is always going to give you way better results than a device will because it is able to use the full processing power and memory of your system. You'll usually get flawed results this way. Whenever you are doing CoreGraphics drawing in conjunction with CoreAnimation it is important to test the results on a real device.

For this you can try to run your app in Instruments Core Animation Tool to try to find culprits. Check out my tutorial on it.

Instruments – Optimizing Core Animation

MobileOverlord
  • 4,580
  • 3
  • 22
  • 30
  • This answer helped me along. I'm allowing users to change the `MagnificationFilter` of a `UIImageView.Layer` at run-time. It worked in the emulator, but the display would not update on the device. Enabling `ShouldRasterize` resolved the issue for me. – Jacob Foshee Jun 11 '12 at 20:26