Re: Drawing many different strings quickly
Re: Drawing many different strings quickly
- Subject: Re: Drawing many different strings quickly
- From: Graham Cox <email@hidden>
- Date: Mon, 28 Sep 2015 12:39:23 +1000
Hi Ben,
You may find that responsive scrolling is actually making things worse in this case, because many more strings than you can see are being drawn, and string drawing is expensive. Have you tried opting out of responsive scroling?
Apart from that, usual advice applies - draw the very minimum you need for the dirty area of the view. Strings are problematic, in that the bounding rectangle is hard to know in advance - calculating that requires the string be laid out, and there goes your time. Note that [NSString drawInRect:attributes:] creates a NSLayoutManager and associated components, does the drawing, then discards all the layout stuff, so it’s very inefficient. Your idea of reusing a NSLayoutManager for all your strings should give better performance, because a) you’re not recreating it every time and b) it caches quite a lot of layout info between calls (which is why you saw a speed up when the strings were the same).
You could try some additional caching of your own, e.g. the bounding rect of a known string, so that you can tell without needing layout again whether the string intersects the dirty region of the view (as tested by -needsToDrawRect:, not whether it intersects the overall dirtyRect). This is only worthwhile if your strings are repeated frequently enough, it’s not going to help if they’re all different. You could also try precalculating the bounding rects on a separate thread rather than doing that as part of drawing/scrolling so that the drawing part isn’t held up by the calculation. It can mean labels “pop in” to view as you scroll which might be unacceptable.
Getting this to perform well is hard, but it can be done. One of my apps draws maps which can consist of many, many thousands of textual labels drawn at arbitrary positions in varying styles. Using tricks as described it scrolls smoothly.
—Graham
> On 28 Sep 2015, at 3:42 am, Ben <email@hidden> wrote:
>
> Hi list,
>
> I'm needing to draw somewhere in the order of 1,000,000 different strings in a scrollable grid view and am struggling to get performance that I am happy with.
>
> After profiling, most of my time is spent in drawing text into the view.
>
> My first attempt was simply to use NSString's drawInRect:withAttributes:. The attributes dictionary was cached between calls. This is not too bad for shorter strings, but slows down dramatically once longer strings need to be drawn truncated.
>
> My second attempt has been to use my own NSTextStorage/Container/LayoutManager trio and draw using NSLayoutManager. This is faster when many strings are the same, but worse when most are different. I don't know in advance what the strings will be so must assume they are all unique.
>
>
> Can anyone suggest what I should look into next? My requirements are as follows:
>
> - Assume around a million unique strings to be drawn
> - Not all strings to be drawn at once, a scroll view is being used and I am using responsive scrolling to pre-draw areas. The problem occurs when quickly scrolling a large distance
> - Longer strings will be truncated to a single line under 200px wide
> - All strings to be drawn in the same font/size/colour
> - I can target the current (or current+1) OS version if that makes any difference
>
>
> Any pointers or suggestions gratefully accepted!
>
> - Ben
> _______________________________________________
>
> Cocoa-dev mailing list (email@hidden)
>
> Please do not post admin requests or moderator comments to the list.
> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>
> Help/Unsubscribe/Update your Subscription:
>
> This email sent to email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden