Drawing controls in code, unless you gain something other than the space saved for bitmaps, is a waste of time and energy. You gain nothing by drawing the gradients for buttons in code.
If it all ends up in that format anyway, you might as well do what Apple does 95% of the time: just use bitmaps. In mobile, saving cycles is more important than saving storage.
Except the ability to resize your UI widgets. If your UI is almost entirely static, then sure, bundling a buttload of images is fast, easy on your designers, and your engineers won't hate you.
But if your UI is of the sort that has highly variable sizing and layouts, then you probably do want to start writing custom draw code that removes you from having to maintain a hundred variants of the same asset in your bundle - say, multi-line gradient buttons. It also allows easier abstraction (say, tinted gradient buttons) without your designer having to painstakingly generate what is essentially the same asset save one feature.
Programmatic UIs also make it easier to do related A/B tests - otherwise testing a button's color would involve shipping updates with every candidate in the bundle.
Like all things, be judicious and smart - though the trend I'm noticing is that we're moving beyond simple UIs on iOS, and there's increasing demand for the sort of UIs that demand this level of flexibility. The performance of recent iOS devices have also been such huge leaps that the penalty of not using pre-baked images everywhere is minimal in most cases.
Custom drawing also has a lot of optimization use - this is a surprising little-known trick for custom UITableViewCells. Compositing is still a very heavy load, avoid having complex view hierarchies for high-performance UI components (a UITableViewCell is high perf in most instances). Consider flattening your views into something that fits into your drawRect call - drawing text directly instead of UILabels, drawing images directly instead of UIImageViews, etc.
Also, a surprisingly little known trick is CALayer.shouldRasterize - setting this flag will rasterize everything in that layer and below and cache it. This incurs a heavier hit on redraw, but for objects that do not need to be redrawn often it's worth it - this allows you to have baked-image performance while still doing custom drawing.
Also, calling -imageNamed to load your images will automatically cache the contents. Numerous Apple engineers have told me not to draw UIs in code and just to use images instead, so although it's a fun challenge, there really is no upside. Even animations in iOS like the jiggling/opening trash are just a series of PNGs using UIImageView animation.
there are plenty of upsides to drawing UIs in code. You get resizable controls, controls you can change the color on, controls that can be added easier programatically, and smaller app bundles.
> "You also have that with images, so that does not apply."
No, it very much still does. The only sort of resizing you get with images is whatever neatly fits within a 9-patch.
Which is to say, if your center patch is non-uniform (gradient? textured surface?) you lose resizability.
So yes, if you design a very standard UI that sails very close to the default iOS look and feel, you will be using stretchable images for almost everything. Which is to say, single-line elements that do not resize vertically at all, vertical linear gradients as an aesthetic theme instead of texturing (which is becoming a thing now), etc.
The moment you depart those shores though, images start becoming a liability instead of an asset, and you'll need to do a lot more custom work to get your widgets to resize properly.
Using bitmaps also has the advantage that the bitmaps can be shared when the control is displayed more than once. It doesn't matter so much for the newest 1GB devices, but on older devices that only have 128 or 256MB it can make a difference.
If it all ends up in that format anyway, you might as well do what Apple does 95% of the time: just use bitmaps. In mobile, saving cycles is more important than saving storage.