11th
Notes on Effective iPhone App Development

Senior Apple Engineer Larry Coopet spoke on Effective iPhone App Development at the Toronto iPhone Tech Talks.
I attended the “Part Two” of this talk after Eric Hope’s iPhone User Interface Design Essentials.
And I took some notes.
“Did you know we have a single function call that does that for you already?”
Coopet opened with a story of a developer who had written reams of code that wasn’t quite working, and then was crushed to learn Apple had already implemented the functionality for him.
“If I see two pages of code, you’re doing it wrong.”
That pretty much summarizes the talk: The frameworks are Apple’s secret weapon. Use them. I later spoke with Coopet. Lots of developers seem unaware of the documentation and examples, let alone the wealth of frameworks and APIs available to get things done.
“If I see more than three or four lines of code, I get nervous.”
Simply your code. It’s the absolute fastest way to get results. “10% is a nice bump for a one-line fix.”
Now, some details.
“Flatten drawing with a custom view.” This is exactly the same advice Google gave for Android at Google I/O: the framework layouts are generic because they don’t know your data. You do. Draw it yourself, don’t nest generic views in generic views. Note you’ll have to take care of landscape mode if you go this route, too.
Minimize drawing. Use setNeedsDisplayInRect:, respect the incoming Rect in drawRect (don’t draw outside it!) and never call DrawRect: directly.
View.opaque is YES by default for a reason! Transparency is expensive (again, the same is true for Android or any other platform.) “People turn this off without understanding, and then wonder why their app is so slow.”
And if you leave your view as opaque, the framework engineers are smart enough to render everything in a way that lets SelectedBackgroundView etc. show through your “opaque” view. Slide showing exploded 3D rendering of a UITableView with various layers. There is a lot going on! (…wish I could draw faster…)
The transition from selected to unselected mode in a table view is not atomic. “Not atomic” means it doesn’t snap from selected to unselected mode in one step.
There is an animation, roughly 250 milliseconds long, that fades out SelectedBackgroundView when the cell loses focus. The text flips color from selected to unselected halfway through that animation.
This was a Holy Shit moment for me. It hints at the attention to detail Apple lavishes on their frameworks for something most people are not going to notice. If you’ve read this far you’re not most people, are you?
It may sound stupid, but remember .png and .jpg are compressed data formats. So you have to multiply the width, height, and bit depth to calculate memory usage. The size of a compressed file on disk is irrelevant. (I’ve had to explain this many times…)
Understand the difference between loading UIImage data using ImageNamed: vs. ImageWithContentsOfFile:
ImageNamed: blocks. You don’t want to use it for lots of images all at once. It’s meant for UI components, so it caches.
ImageNamed: used for nib references, for example. Use one nib per view controller, not, say sixteen. Load your views dynamically (“lazy instantiation”)
ImageWithContentsOfFile: is for user content. No cache. So you’re not going to fill memory with cached copies of these images. It may seem slower. Avoid caching or resizing large images.
Some Apple documentation is available forUIImage.
Underneath UIImage is CGImage. (“UI wraps CG. This is a common iPhone theme.”) Since UIImage is a lightweight wrapper, you have trivial access to the underlying implementation. You can move up and down the API depending on what you need to do. (Desktop developers wish they had UIKit sometimes, while iPhone developers reach down into Core for more control.)
Adding concurrency. “Yes, even on a single core.”
- XML parsing
- image manipulation
- significant disk I/O (“especially non-uniform data”)
- importing data
(Some people noted Coopet held up his iPhone and said “even this” would be multicore someday, but I believe in this context he was reflecting a common assumption rather than making a surprise product announcement.)
“Don’t block the user.”
“Instrument before you decide” —concurrency might not be a win. You should probably avoid concurrency when
- networking (“use asynchronous callbacks instead”)
- initWithContentsOfURL (“someone might change the size on you!”)
- don’t wait on a thread
Use NSTimer, not idle threading. Waiting in parallel doesn’t speed things up.
Coopet told a story about an application that was loading an image over the network. Someone on the server side substituted a much larger image, and the application crashed after being submitted to Apple since it hadn’t been coded to handle that condition.
One Thread, One Object. Confinement via NSOperation.
NSOperation gives completely object-oriented encapsulation. Everything you need: code & data, state, depndencies, priority. It’s easy to add to existing code (“but you still have to write the code.”) And you might be forced to refactor your code, which is good. NSOperationQueue. Grand Central Dispatch is admittedly cool, but it’s not available for iPhone, and NSOperation gives a lot of power already that people are not taking advantage of.
“Shared data is an extremely bad idea” —unless you have 20 years of experience working with concurrency. Maybe not even then.
Break up your data. Pass sub-arrays, for example.
Delegation versus Notification. Notifcation is for one-to-many.
UIKit can only be (safely) run on the main thread.
In general, you can perform as many operations as you have cores, plus one.
See Apple’s documentation on NSOperation and the Concurrency Programming Guide
Coopet walked through a detailed example which unfortunately may not be available on Apple’s site. “Check out the LazyTableImages example.”
Coopet used NSOperation to load and rescale very large images as thumbnails, on demand, in a scrolling table view. Small changes had big effects on performance. Scrolling was fast even with a transparent gradient over a photographic background. Very impressive.
Coopet is VERY liberal with isCancelled, sprinkled throughout his code so he can stop working as quickly as possible. (From Apple’s NSOperation Class Reference: “isCancelled key path lets clients know that the cancellation of an operation was requested. Support for cancellation is voluntary but encouraged and your own code should not have to send KVO notifications for this key path.”)
“Check isCancelled. A lot.”
Coopet closed with a discussion about system view hierarchies and private APIs, which are a hot topic with the iPhone developer community right now.
“The supported way… is to insert yourself in the chain of events and use delegation. You cannot consume an event.” Call [super] first, look but don’t touch, and be quick about it. Write event-independent code.
Do not attempt to cache multitouch events. They’re ephemeral.
Use the new 3.1 API updates.
“Stop hacking the view hierarchy!”
I spoke with Larry Coopet at the wine and cheese reception at the end of the day. He was very approachable. If you do attend an Apple event, by all means, seek out the speakers if you get the chance. This guy’s been writing software for 30 years and likes to talk about it.
Next up will be notes from Allan Schaffer’s talk on Open ES, a topic which is “easy to learn, but hard to master.”