When to Draw
Although iOS drawing is a fairly common task for developers, the task itself is not very general. Most drawing is limited to certain specific arenas, namely four extremely common scenarios where it makes sense to work directly with graphics: creating custom views, building images, creating PDFs, and building with Core Graphics.
Creating Custom Views
Every UIKit view is, essentially, a blank canvas. You can fully customize a view by drawing whatever contents best express the view’s role in your application. You do this by drawing that content in a special method called drawRect:. This method enables you to customize a view’s look by calling UIKit and Quartz drawing routines.
Figure 1-1 shows a custom color control. It consists of a deck of swatch views, each of which is a UIView subclass that implements the drawRect: method. These views draw the border with its rounded edges, the informational text, and the splash of color to create a fully realized, yet fully custom, look.
Figure 1-1 These swatches are drawn by custom drawRect: methods.
Unless you override it in a subclass, the default drawRect: method basically does nothing. Subclasses that create a presentation using UIKit and Core Graphics routines override this method. They add their drawing requests to their subclass implementation. Simple views that merely update a background color or that supply content in other ways apart from drawing should not override drawRect:. Similarly, OpenGL ES-powered views do not use this entry point for drawing.
The drawRect: method has a close cousin that is meant only for printing: drawRect:forViewPrintFormatter: allows you to customize content that should print differently than it displays.
Not every image starts its life as a PNG or JPEG file. On iOS, you can draw into a UIKit image context and retrieve a UIImage instance. This enables you to create new images or modify existing images.
Figure 1-2 shows a programmatically constructed color wheel. This image was created via a series of colored Bezier path arcs drawn into a UIKit image context. The resulting image was then added to a standard image view. Drawing allows you to build custom images as you need them without having to rely on a preexisting library of image files.
Figure 1-2 This color wheel was built from code into a custom UIImage.
Code-based drawing makes an important trade-off. Although you need greater processing time to create images (not a huge amount, but its measurable), you end up with a slimmer application bundle, with fewer required resources. Your images are far more flexible—limited only to the code you use to create them.
The same kinds of calls that help you build images also support PDF creation. You can draw into a UIKit PDF context, which is either sent directly to a file or saved to data. This enables you to build PDF content from your apps and then share them, store them, or display them, as in Figure 1-3.
Figure 1-3 A multipage PDF is previewed in this iOS 6 popover.
PDFs provide a highly portable, system-independent standard that encapsulates a complete document description. The document you create on iOS looks the same, more or less, on any computer you use to view it. The operating system’s color management system may affect color presentation.
Building with Core Graphics
When you hit the edges of UIKit’s current capabilities, you can fall back to standard Quartz. Core Graphics has been around a long time, and its drawing features have powered OS X for a decade. Any feature that isn’t immediately tweakable in UIKit is almost always available through Quartz.
Drawing items into a Core Graphics context provides flexible and powerful drawing solutions—even if they’re not quite as simple as their UIKit siblings. Core Graphics uses Core Foundation-style C-based objects and requires manual retain and release development strategies.
For example, you might want to access image data on a byte-by-byte level. That’s a task that isn’t well handled by UIKit (yet!) but is perfect for Core Graphics’s bitmap contexts. Figure 1-4 shows an example of why you might turn to Quartz functions. In this example, the RGB image on the left is rendered into a grayscale color space using Core Graphics.
Figure 1-4 The routine that transformed this RGB image to a grayscale representation was written using Core Graphic primitives.
The resulting images must be transformed from Quartz CGImageRef (CG types that end with Ref are pointers to objects) into UIImage instances (imageWithCGImage:) and displayed in a standard image view.