My first step was to switch to using CoreText, a lower level API for rendering text. This reduced overheads by around 50%.
My second step was to cache layout information for recently displayed strings in a small cache. Tables often contain a lot of repeated values so this saved a lot of time; in some cases up to 70%.
After these optimizations, my own code was no longer the bottleneck. I still don't reach 60FPS on my 2009 Macbook Pro, but that was expected...
(Note: 60FPS scrolling is not a problem if your views are smallish, so that they can be entirely cached on the GPU; the problem occurs only when your views are very large and the users scrolls very fast so that the CPU can't keep up with rendering tiles for the GPU)