Clicky

iOS Dev Nugget 275 Implementing UIView draw(_:)

.

Need to run a code review on your codebase? Hire me

If you perform your own custom view draw by overriding UIView draw(_:) in your subclass, and you trigger it by calling setNeedsDisplay(_:), it's a performance boost if you restrict drawing to just the dirty rectangle passed to draw(_:):

override func draw(_ rect: CGRect) {
    //Only draw inside rect, and not the entire UIView specified by the `bounds` property
}

On macOS, the functions getRectsBeingDrawn(_:count:) and needsToDraw(_:) can be used to discover whether you want to draw, but they are not available on iOS.

I've found that a simple way the handle this is to set the dirty rect as the clipping region:

override func draw(_ rect: CGRect) {
    let context = UIGraphicsGetCurrentContext()
    context?.saveGState()
    let path = UIBezierPath(rect: rect)
    path.addClip()
    //Perform your drawing in `bounds` here
    context?.restoreGState()
}

I'm recently building an app that involves panning many views that implement custom drawing and just introducing clipping makes the performance improve from being dog slow to buttery smooth.

And if you want to go one step further, you can use the "context" technique I mentioned in #168 to clean up the code:

Implement this:

func withGraphicsContext(block: (CGContext?) -> ()) {
    let context = UIGraphicsGetCurrentContext()
    context?.saveGState()
    block(context)
    context?.restoreGState()
}

And you can rewrite draw(_:):

override func draw(_ rect: CGRect) {
    withGraphicsContext { context in
        let path = UIBezierPath(rect: rect)
        path.addClip()
        //Perform your drawing in `bounds` here
    }
}

There is a technote which mentions:

Each UIView is treated as a single element. When you request a redraw, in part or whole, by calling -setNeedsDisplayInRect: or -setNeedsDisplay:, the entire view will be marked for updates

I did some testing and it seems like the statement is either outdated or wrong. But even if it becomes true in the future, clipping wouldn't break your code. So happy drawing!

Your feedback is valuable: Do you want more nuggets like this?   Yes   or   No

.

.

Like this and want such iOS dev nuggets to be emailed to you, weekly?

Sign Me Up! or follow @iosdevnuggets on Twitter

.

View archives of past issues