简体   繁体   中英

NSAttributedString draw(in: rect) in Swift have poor performance?

I have an UIView that might contain over 400-500 string on screen simultaneously. And this UIView is scrollable. The first decision is to use UICollectionView with a custom layout. And it works great when items in the UIcollectionView are not more than 30-50 on the screen simultaneously. If I squeeze the UIView (by pinch gesture) and it has over 100-150 items on the screen simultaneously, I have lags when try to scroll (frame rate is down and draw for 1 frame take more than 20-50 ms).

Ok. Then I decide to draw UIView absolutely manually. For draw shapes, I use CGContext (works great even I draw 1000-2000 shapes simultaneously). But when I try to draw many strings (100-300) with NSAttributedString draw(in: rect) it gives a very bad performance while scrolling.

Drawing 50 strings (frame rate is ok, near 16ms for drawing) 在此处输入图片说明

Drawing 150 strings (frame rate is bad, near 30ms for drawing) 在此处输入图片说明

Drawing 300 strings (frame rate is bad, near 60ms for drawing) 在此处输入图片说明

So, the question is Why NSAttributedString draw(in: rect) in Swift have poor performance? Even when I add 300 UILabel to View simultaneously and try to scroll its frame rate is ok (not more 17ms per frame). How UILabel draw text inside for having high performance while the screen is redrawing?

Doing your own drawing is not a performance improvement in most cases.

UILabel is fast because it has to draw the string exactly once. It then keeps a bitmap image of the drawn string in its backing store. This will be reused for every frame afterwards. Also the compositing of all the view bitmaps will be done via the GPU.

If you do your own drawing you most likely can't benefit from the cached backing store. Having to redraw the whole view is slow, as you just noticed. It can be improved by only redrawing the parts that actually changed (use setNeedsDisplay(rect) ), but this is generally not possible when zooming. Manually drawing is slow because all the Core Graphics APIs you use for this run on the CPU, not the GPU.

Your approach of using a collection view with a custom layout should be able to handle this just fine. It's not easy to write a collection view layout that performs well, but it is possible. Maybe you should investigate this with instruments and then ask another question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM