In March we talked about our intention to start writing articles about the new iPhone OS 3.0 ... and immediately came to a screeching halt as we discovered that Apple had updated their NDA to prevent discussion of prerelease versions of the SDK.
Now, fortunately, iPhone OS 3.0 has been officially released, and so we can start talking about what's changed from when we wrote iPhone in Action. One of the biggest differences shows up in UITableViewCells, with the entire old way to do things being deprecated (though still functional at this time).
Here's what you should know:
Creating Table Cells
We talked about how to fill in a cell for a table on p.235 of iPhone in Action. As of 3.0, however, you no longer work with a bare cell, but instead can use a stylized cell, which will allow you to arrange up to four data elements (two text labels, one image, and one accessory view) in standardized ways. To do so, you create your cell with a new init function:
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier] autorelease];
The style can be set to one of four types:
- UITableViewCellStyleDefault creates a old-style cell with just one label.
- UITableViewCellStyleValue1 includes two labels, a black one to the left and a blue one to the right, just like the Settings cells that we talked about in a previous article.
- UITableViewCellStyleValue2 does the opposite, putting a blue label to the left (and right justifying it) and a black label to the right (and left justifying it), like is shown for the Info page of individual contacts.
- UITableViewCellStyleSubtitle puts one line of text in black, then another below it in gray, allowing much the same functionality as shown in our beautiful tables post.
Besides these one or two labels, you can also automatically insert a picture to the left of each table cell and (of course) an accessory to the right. Those are available in all styles.
Accessing the Cell Views
The other big change in cell is how you access its elements. You should no longer be using the simple image and text properties that you depended on in 2.x. Instead, a set of three properties give you access to the actual objects that make up the cell, allowing you to change any of their properties. imageView contains the UIImageView placed to the left, textLabel contains the UILabel for the main (or only) text and detailTextLabel contains the UILabel for the subsidiary text (if there is such). You can manipulate those as you see fit.
Here's an example of some code that fills in both text labels and an image in a subtitle-styled box.
cell.textLabel.text = [textLabelContents objectAtIndex:indexPath.section];
cell.textLabel.font = [UIFont boldSystemFontOfSize:14];cell.detailTextLabel.text = [detailLabelContents objectAtIndex:indexPath.section]
cell.imageView.image = [imageList objectAtIndex:indexPath.section];
Note that I can change not only the text and image properties of these objects, but also other things, such as the font change shown for textLabel.
This setup has advantages and disadvantages.
On the good side, it's a lot easier to do somewhat more complex things, which should save you a lot of programming time for the standard styles that you develop for filling in table cells.
On the bad side, because so much is done for you, you can end up kind of constrained. For example, I set the textLabel to a font size of 14 in the code above, which is pretty small. The problem is that the whole style is really set up for a larger text size, and so this leaves more space than I'd like between the two lines of text. I suppose I could next go through and move the UILabels around and shrink the rowHeight ... but at a certain point I start to wonder if I should just create my own UITableViewCell subclass from scratch.
Of course, even doing that's probably simpler as long as you start with one of these styles ...
About 3.0 Deployment
When I started thinking about coding with new 3.0 API elements, my first concern was whether I'd be cutting off potential customers by doing so. Fortunately, this doesn't seem to be a concern. The tapbots blog shows a 75% adoption rate of 3.0 over the first 5 days.
That's high enough that I have no qualms about working on new programs using 3.0, though I'd be a bit more careful updating old programs, until that rate gets to 90% or so.
(The biggest problems seems to be Apple's decision to charge iPod users $10 to upgrade their OS.)

Animating Sublayers
In iPhone in Action we talked about two ways that you can animate graphics in your apps.
First, we talked about Quartz (pp.367-391). Although we didn't specifically talk about using it for animation, the methodology should be obvious: by redrawing your CALayer in slightly different ways, you can explicitly create an animation.
Second, we talked about Core Animation (pp. 391-394). It makes animation a lot easier, because if you want to animate something in a standard way (such as by adjusting its position or its opacity) you can do so just by changing that value, then having the SDK implicitly create the animation for you.
So, what do you do if you want to create a Quartz drawing (some of which might animate explicitly--or not) that itself contains simple, implicit animations? That's what this article will talk about.
From Quartz to Core Animation
The secret lies in the use of sublayers. We briefly touch upon this on p.392, where we note that you can add sublayers to a layer and then animate the individually. (We also warn about sublayers having inverted coordinate systems, which is no longer the case, as far as I can see.) However, we don't give details because (as ever) there's limited space in a print book.
So, here are the details:
You can easily create a sublayer as part of a drawRect: method call in a UIView subclass. Here's an example of creating a subview that has an arrow drawn on it:
There are broadly three steps to creating a sublayer. First, you create the sublayer with the [CALayer layer] message, usually followed by a message to set its frame size. Second, you create the sublayer's content. Third, you add the new layer as a sublayer to your existing CALayer.
Step one requires one additional note. Be aware that we only create this sublayer if it hasn't been created previously. This is a similar methodology to our discussions of creating subviews of a table, several weeks back.
The trickiest element, however, is in step two, because there aren't a lot of easy ways to add content to a sublayer without creating a whole subclass of CALayer, then creating its content there. Though that's surely possibly, it's nice to keep all of your drawing of layers and sublayers together, thus I offer up a pretty good alternate methodology here: create a bitmap content, draw to it, and save it (using the same techniques we discussed on pp.383-384), then set the content property of your sublayer to the CGImage you create from your bitmap.
Animating Your Sublayer
From this point,animating your sublayer should be largely trivial, following our Core Animation example from iPhone in Action. Here's some snippets of code that are used to animate the subview.They appear in touchesMoved:withEvent:
As you can see, this is very similar to the airplane example we used on p.392, with opacity and movement both being animated. The biggest change is that we work with a property that we don't mention in the book, autoreverses. That tells the animation to go all the way forward, then back out too. In this case it moves an arrow to the left, and then back (which I use in the program to help cue a user that he's moving a strip of icons in that direction).
As always, Core Animation is simple and quick. The only trick in this bit of code for me was figuring out how to create the sublayer and populate it correctly. Beyond that, you existing Core Animation knowledge should work fine.
Posted by Shannon Appelcline at 02:33 PM in iPhone in Action Commentary | Permalink | Comments (1) | TrackBack (0)