For the More Curious: Layers, Bitmaps, and Contexts

A layer is simply a bitmap – a chunk of memory that holds the red, green, blue, and alpha values of each pixel. When you send the message setNeedsDisplay to a UIView instance, that method is forwarded to the view’s layer. After the run loop is done processing an event, every layer marked for re-display prepares a CGContextRef. Drawing routines called on this context generate pixels that end up in the layer’s bitmap.

How do drawing routines get called on the layer’s context? After a layer prepares its context, it sends the message drawLayer:inContext: to its delegate. The delegate of an implicit layer is its view, so in the implementation for drawLayer:inContext:, the view sends drawRect: to itself. Therefore, when you see this line at the top of your drawRect: implementations,

-​ ​(​v​o​i​d​)​d​r​a​w​R​e​c​t​:​(​C​G​R​e​c​t​)​r​
{​
 ​ ​ ​ ​C​G​C​o​n​t​e​x​t​R​e​f​ ​c​t​x​ ​=​ ​U​I​G​r​a​p​h​i​c​s​G​e​t​C​u​r​r​e​n​t​C​o​n​t​e​x​t​(​)​;​
}​

you are getting a pointer to the layer’s context. All of the drawing in drawRect: is filling the layer’s bitmap, which is then copied to the screen.

Need to see this for yourself? Set an Xcode breakpoint in HypnosisView’s drawRect: and check out the stack trace in the debug navigator, as shown in Figure 22.8.

Figure 22.8  Stack trace in drawRect:

Stack trace in drawRect:

A few paragraphs up, we said that the pixels generated by drawing routines end up in the layer’s bitmap. What does that mean? When you want to create a bitmap context in Cocoa Touch (as you did when you created the thumbnails for the possessions), you typically do something like this:

 ​ ​ ​ ​/​/​ ​C​r​e​a​t​e​ ​c​o​n​t​e​x​t​
 ​ ​ ​ ​U​I​G​r​a​p​h​i​c​s​B​e​g​i​n​I​m​a​g​e​C​o​n​t​e​x​t​W​i​t​h​O​p​t​i​o​n​s​(​s​i​z​e​,​ ​N​O​,​ ​[​[​U​I​S​c​r​e​e​n​ ​m​a​i​n​S​c​r​e​e​n​]​ ​s​c​a​l​e​]​)​;​
 ​ ​ ​ ​ ​ ​ ​ ​.​.​.​ ​D​o​ ​d​r​a​w​i​n​g​ ​h​e​r​e​ ​.​.​.​

 ​ ​ ​ ​/​/​ ​G​e​t​ ​i​m​a​g​e​ ​r​e​s​u​l​t​
 ​ ​ ​ ​U​I​I​m​a​g​e​ ​*​r​e​s​u​l​t​ ​=​ ​U​I​G​r​a​p​h​i​c​s​G​e​t​I​m​a​g​e​F​r​o​m​C​u​r​r​e​n​t​I​m​a​g​e​C​o​n​t​e​x​t​(​)​;​

 ​ ​ ​ ​/​/​ ​C​l​e​a​n​ ​u​p​ ​i​m​a​g​e​ ​c​o​n​t​e​x​t​
 ​ ​ ​ ​U​I​G​r​a​p​h​i​c​s​E​n​d​I​m​a​g​e​C​o​n​t​e​x​t​(​)​;​

A bitmap context is created and drawn to, and the resulting pixels are stored in a UIImage instance.

The UIGraphics suite of functions provides a convenient way of creating a bitmap CGContextRef and writing that data to a UIImage object:

 ​ ​ ​ ​/​/​ ​C​r​e​a​t​e​ ​a​ ​c​o​l​o​r​ ​s​p​a​c​e​ ​t​o​ ​u​s​e​ ​f​o​r​ ​t​h​e​ ​c​o​n​t​e​x​t​
 ​ ​ ​ ​C​G​C​o​l​o​r​S​p​a​c​e​R​e​f​ ​c​o​l​o​r​S​p​a​c​e​ ​=​ ​C​G​C​o​l​o​r​S​p​a​c​e​C​r​e​a​t​e​D​e​v​i​c​e​R​G​B​(​)​;​

 ​ ​ ​ ​/​/​ ​C​r​e​a​t​e​ ​a​ ​c​o​n​t​e​x​t​ ​o​f​ ​a​p​p​r​o​p​r​i​a​t​e​ ​w​i​d​t​h​ ​a​n​d​ ​h​e​i​g​h​t​
 ​ ​ ​ ​/​/​ ​w​i​t​h​ ​4​ ​b​y​t​e​s​ ​p​e​r​ ​p​i​x​e​l​ ​-​ ​R​G​B​A​
 ​ ​ ​ ​C​G​C​o​n​t​e​x​t​R​e​f​ ​c​t​x​ ​=​
 ​ ​ ​ ​ ​ ​ ​ ​C​G​B​i​t​m​a​p​C​o​n​t​e​x​t​C​r​e​a​t​e​(​N​U​L​L​,​ ​w​i​d​t​h​,​ ​h​e​i​g​h​t​,​ ​8​,​ ​w​i​d​t​h​ ​*​ ​4​,​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​c​o​l​o​r​S​p​a​c​e​,​ ​k​C​G​I​m​a​g​e​A​l​p​h​a​P​r​e​m​u​l​t​i​p​l​i​e​d​L​a​s​t​)​;​

 ​ ​ ​ ​/​/​ ​M​a​k​e​ ​t​h​i​s​ ​c​o​n​t​e​x​t​ ​t​h​e​ ​c​u​r​r​e​n​t​ ​o​n​e​
 ​ ​ ​ ​U​I​G​r​a​p​h​i​c​s​P​u​s​h​C​o​n​t​e​x​t​(​c​t​x​)​;​

 ​ ​ ​ ​.​.​.​ ​D​o​ ​d​r​a​w​i​n​g​ ​h​e​r​e​ ​.​.​.​

 ​ ​ ​ ​/​/​ ​G​e​t​ ​i​m​a​g​e​ ​r​e​s​u​l​t​
 ​ ​ ​ ​C​G​I​m​a​g​e​R​e​f​ ​i​m​a​g​e​ ​=​ ​C​G​B​i​t​m​a​p​C​o​n​t​e​x​t​C​r​e​a​t​e​I​m​a​g​e​(​c​t​x​)​;​
 ​ ​ ​ ​U​I​I​m​a​g​e​ ​*​r​e​s​u​l​t​ ​=​ ​[​[​[​U​I​I​m​a​g​e​ ​a​l​l​o​c​]​ ​i​n​i​t​W​i​t​h​C​G​I​m​a​g​e​:​i​m​a​g​e​]​ ​a​u​t​o​r​e​l​e​a​s​e​]​;​

 ​ ​ ​ ​/​/​ ​C​l​e​a​n​ ​u​p​ ​i​m​a​g​e​ ​c​o​n​t​e​x​t​ ​-​ ​m​a​k​e​ ​p​r​e​v​i​o​u​s​ ​c​o​n​t​e​x​t​ ​c​u​r​r​e​n​t​ ​i​f​ ​o​n​e​ ​e​x​i​s​t​s​
 ​ ​ ​ ​U​I​G​r​a​p​h​i​c​s​P​o​p​C​o​n​t​e​x​t​(​)​;​
 ​ ​ ​ ​C​G​I​m​a​g​e​R​e​l​e​a​s​e​(​i​m​a​g​e​)​;​
 ​ ​ ​ ​C​G​C​o​n​t​e​x​t​R​e​l​e​a​s​e​(​c​t​x​)​;​
 ​ ​ ​ ​C​G​C​o​l​o​r​S​p​a​c​e​R​e​l​e​a​s​e​(​c​o​l​o​r​S​p​a​c​e​)​;​

A layer creates the same kind of context when it needs to redraw its contents. However, a layer does it a little differently. See the NULL as the first parameter to CGBitmapContextCreate? That is where you pass a data buffer to hold the pixels generated by drawing routines in this context. By passing NULL, we say, Core Graphics, figure out how much memory is needed for this buffer, create it, and then dispose of it when the context is destroyed. A CALayer already has a buffer (its contents), so it would call the function as follows:

 ​ ​ ​ ​C​G​C​o​n​t​e​x​t​R​e​f​ ​c​t​x​ ​=​
 ​ ​ ​ ​ ​ ​ ​ ​C​G​B​i​t​m​a​p​C​o​n​t​e​x​t​C​r​e​a​t​e​(​m​y​B​i​t​m​a​p​P​i​x​e​l​s​,​ ​w​i​d​t​h​,​ ​h​e​i​g​h​t​,​ ​8​,​ ​w​i​d​t​h​ ​*​ ​4​,​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​c​o​l​o​r​S​p​a​c​e​,​ ​k​C​G​I​m​a​g​e​A​l​p​h​a​P​r​e​m​u​l​t​i​p​l​i​e​d​L​a​s​t​)​;​

Then, when this context is drawn to, all of the resulting pixels are immediately written to the bitmap that is the layer.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.142.2