AppKit drawing uses a notion similar to recursive windows. Each window contains an NSView instance or subclass that covers the entire space allocated for drawing. This can contain other NSViews, each of which can contain others, and so on. When a part of a view becomes out of date, it is sent a -setNeedsDisplayInRect: message that marks the rectangle as needing display. This message is passed up the hierarchy until it reaches the root view in the window. The next time the window is drawn, each view draws the part of itself that overlaps this rectangle in turn into the window buffer.
This is, very roughly, the same mechanism applied to views that pre-Quartz window servers applied to windows. By and large, this works well, but when you come to add animationsfor example, one view sliding over another at 20 frames per secondthe number of redraws becomes very large. Fortunately, this is a problem that Quartz had already solved for windows.
With the iPhone, Apple introduced LayerKit. This framework allowed each view to have its own frame buffer, called a layer. If you wanted to move a view over another, then you were just moving one texture over another, which could be done on the GPU. By modern desktop (or laptop) standards, the iPhone's GPU is pretty anemic. In comparison to the graphics hardware that shipped with the first iMacs, it is incredibly powerful, so this kind of simple effect doesn't come close to taxing it.
The cost, of course, is more RAM usage. The iPhone got around this in several ways. First, it is quite a small device. A frame buffer on the iPhone is only 450KBnot much on a device with 128MB of RAM (or 256MB for the newer ones). The iPhone doesn't permit overlapping windows; it only lets one application control the screen at a time. This means that every other application's layers can be flushed from RAM and regenerated later if there isn't enough space for them. This also means that each application only needs a few percent of the total RAM for its layers.