How to speed drawing a grid of UIViews? - uiview

Currently I instantiate a 2-d matrix of UIViews. Each UIView's drawRect is overridden to draw 1 of 2-3 shapes.
As the grid scales larger, I am noticing excessive time spent in the drawRect of each subview. Since I only have 2-3 shapes, I would like to speed up the rendering of the matrix by drawing the 2-3 unique UIViews each only one time, and then somehow instantiate a copy of the appropriate pre-drawn UIView in the matrix.
I have considered capturing the UIView as a UIImage, making a copy of the UIImage and instantiating this copy. I am wondering though, if the overhead of this process makes it not appreciably faster than drawRect.
Can someone point me to a best practice for speed optimization by reusing UIViews in a 2-D matrix?

The quick fix to this issue is to enable the shouldRasterize property of a given UIView that does not require further updates.

Related

Is there are way to draw a pixel in SpriteKit?

I am trying to put together ray tracing routine and the width/shade of every pixel in a single ray will change over the length of the line. Is there a way in SpriteKit to draw a single pixel on the screen? or should I be doing this using UIImage?
SpriteKit isn't a pixel drawing API. It's more of a "moving pictures around on the screen" API. There are a couple of cases, though, where it makes sense to do custom drawing, and SpriteKit (as of iOS 8 and OS X 10.10) has a few facilities for this.
If you want to create custom art to apply to sprites, with that art being mostly static (that is, not needing to be redrawn frequently as SpriteKit animates the scene), just use the drawing API of your choice — Core Graphics, OpenGL, emacs, whatever — to create an image. Then you can stick that image in an SKTexture object to apply to sprites in your scene.
To directly munge the bits inside a texture, use SKMutableTexture. This doesn't really provide drawing facilities — you just get to work with the raw image data. (And while you could layer drawing tools on top of that — for example, by creating a CG image context from the data and rewriting the data with CG results — that'd slow you down too much to keep up with the animation framerate.)
If you need high-framerate, per-pixel drawing, your best bet is to do that entirely on the GPU. Use SKShader for that.
If your application is redrawing every frame, then you can use an offscreen buffer to dynamically update pixels, aka SKMutableTexture. I'm not sure how slow it will be.

Best Practice for interactive 2D programming way in iOS

I want to create a diagram application, I can create some shapes.
Every shape can be moved in the canvas.
What is the best way to implement it? Now I know is just two way:
with only UIView, draw all shapes in this UIView. When touch events
reached, redraw everything.
Create a UIView for each Shape, and every UIView can response UIEvent independently
Is there any other good way? The first is too complicated. The second seems has bad performance ?
Either will work, but each have pros and cons. Specifically:
Single UIView: This approach would require you to create a CALayer for each shape and then do your own hit-testing and finger-dragging when the shape is moved. This approach will perform much better if you have many shapes (be sure to use an indexed lookup to do hit testing rather than an O(N) search) since CALayers are lightweight.
Do not take the approach o drawing the shapes in their current location in a single UIView via a single call to drawRect:. This will perform extremely poorly, especially when you are move the shapes during a drag, and as you indicate, is very complicated to implement well
One UIView Per Shape: This approach is very easy to program, as you don't have to do the hit-testing and the touch get's sent to the shape being touched. This approach will perform well if you have a few shapes (<30, in my experience). If you have a large number of shapes, you start to see issues with frame rate.

Which is the fastest way to add a rectangle on the front window

We can draw rectangle on the UIImage. And we can also add a sub-view with a backgroundcolor or border. I guess there is other methods to make it, too.
Did someone try to analyze them?
Which is the fastest way?
Thanks!
I would say, drawing rectangles using Quartz engine and UIImage is more CPU intensive that using UIView. If your scene is heavy and dynamic, Quartz is the best way of doing drawings because you can update your drawings.
Using UIView is not CPU intensive, but it'll have a heavy memory foot print if you want to draw a lot of rectangles.
So, if you want to draw just one or two rectangle for GUI design, I'd say go for using UIViews. But If you are trying to do some complex drawings involving more shapes go for Quartz.

CALayer vs CGContext, which is a better design approach?

I have been doing some experimenting with iOS drawing. To do a practical exercise I wrote a BarChart component. The following is the class diagram (well, I wasnt allowed to upload images) so let me write it in words. I have a NGBarChartView which inherits from UIView has 2 protocols NGBarChartViewDataSource and NGBarChartViewDelegate. And the code is at https://github.com/mraghuram/NELGPieChart/blob/master/NELGPieChart/NGBarChartView.m
To draw the barChart, I have created each barChart as a different CAShapeLayer. The reason I did this is two fold, first I could just create a UIBezierPath and attach that to a CAShapeLayer object and two, I can easily track if a barItem is touched or not by using [Layer hitTest] method. The component works pretty well. However, I am not comfortable with the approach I have taken to draw the barCharts. Hence this note. I need expert opinion on the following
By using the CAShapeLayer and creating BarItems I am really not
using the UIGraphicsContext, is this a good design?
My approach will create several CALayers inside a UIView. Is there a
limit, based on performance, to the number of CALayers you can
create in a UIView.
If a good alternative is to use CGContext* methods then, whats the
right way to identify if a particular path has been touched
From an Animation point of view, such as the Bar blinking when you
tap on it, is the Layer design better or the CGContext design
better.
Help is very much appreciated. BTW, you are free to look at my code and comment. I will gladly accept any suggestions to improve.
Best,
Murali
IMO, generally, any kind of drawing shapes needs heavy processing power. And compositing cached bitmap with GPU is very cheap than drawing all of them again. So in many cases, we caches all drawings into a bitmap, and in iOS, CALayer is in charge of that.
Anyway, if your bitmaps exceed video memory limit, Quartz cannot composite all layers at once. Consequently, Quartz have to draw single frame over multiple phases. And this needs reloading some textures into GPU. This can impact on performance. I am not sure on this because iPhone VRAM is known to be integrated with system RAM. Anyway it's still true that it needs more work on even that case. If even system memory becomes insufficient, system can purge existing bitmap and ask to redraw them later.
CAShapeLayer will do all of CGContext(I believe you meant this) works instead of you. You can do that yourself if you felt needs of more lower level optimization.
Yes. Obviously, everything has limit by performance view. If you're using hundreds of layers with large alpha-blended graphics, it'll cause performance problem. Anyway, generally, it doesn't happen because layer composition is accelerated by GPU. If your graph lines are not so many, and they're basically opaque, you'll be fine.
All you have to know is once graphics drawings are composited, there is no way to decompose them back. Because composition itself is a sort of optimization by lossy compression, So you have only two options (1) redraw all graphics when mutation is required. Or (2) Make cached bitmap of each display element (like graph line) and just composite as your needs. This is just what the CALayers are doing.
Absolutely layer-based approach is far better. Any kind of free shape drawing (even it's done within GPU) needs a lot more processing power than simple bitmap composition (which will become two textured triangles) by GPU. Of course, unless your layers doesn't exceeds video memory limit.
I hope this helps.

CALayer optimizations?

I'm adding several CALayers as sublayers of the layer of a UIView. The contents of each layer is a different image downloaded from a server. Each layer is animated from offscreen to a randomly generated position. The image data is downloaded asynchronously. Each image is approx 300x300 or smaller.
As a result of the random placement, the layers overlap and some are obscured by the layers above them. This is all good.
I'm removing layers as they become completely obscured from view using the suggestion in the answer to this question The calculations to determine coverage occur on a separate thread.
I have a UIPanGestureRecognizer that allows the user to drag the layers around on the screen.
I'm encountering a performance problem when the number of layers added approaches 25-30 and gets progressively worse. The animations become choppy and often are completely absent (the newly added layers simply appear in their final position). And the pan gestures are either ignored or result in choppy repositioning of the selected layer.
I'm supposing that I'm killing the GPU with all of the layers overlapping and another layer animating above?
Any suggestions on how to improve performance?
Best practices for dealing with large numbers of layers?
Is it better to have the layer begin animated in a separate view.layer than the previously added layers?
Thanks!
Couple of quick things to check.
Run the Core Animation Instrument and look for opacity. Just setting the layer's opaque flag to YES is not enough, if the underlying image has an alpha component the layer will take that into consideration.
If the data you are getting from your sever has alpha then you should redraw with Quartz and save the file locally in the new format that does not include alpha.
Make doubly sure that you are not putting 1 mega pixel images into 100x100 tiles. Also Core Animation Instrument, switching on 'Color Misaligned Images' and look for yellow.
30 to 50 layers should be no problem.
If all the layers don't fit in the GPU's memory or portion of memory, things will slow down a lot. Loading and unloading GPU memory is reported to be quite slow compared to compositing layers in GPU memory. You'll have to experiment with this memory limit, as older devices have less GPU memory available than more recent devices.

Resources