I'm not really sure, what am I asking...
...but if make layer composites in separate methods, and draw them to the view also outside of the drawRect: method... ...then could my app performance get raised?
I'm actually subclassed a puzzlePiece:UIView class, where the puzzlepiece gets rendered, but the redraw invoked now with setNeedsDisplay since the drawing implementation takes place in the drawRect: method. The app lags.
Can I improve performance if I get rid of the so called drawRect: method?
The thing wants to get implemented: http://gotoandplay.freeblog.hu/
I think what you want to do here is to have a very single, simple UIView that covers the entire play area. Then put each tile in a CALayer, and attach all the CALayers to the UIView and move them around and rotate them. Then there should not need to be a -drawRect: at all. You'll do all your drawing in your layers, and you should get the best performance that way. CALayer is similar to UIView in principle, but much lighter weight (faster and simpler). CALayer is basically a view that can only draw; it can't handle touches or events. It's parent view has to do that for it. But that let's CALayer be much faster.
Related
I have a custom class which I derived from the UIView class. What I want to accomplish is just drawing vertical black lines with a predefined distance between. When I override the drawRect method and write my code to draw vertical lines, the view just shows a complete black background. Then I noticed that even an empty overridden drawRect which only calls the superclass' drawRect results in a black background. When I comment out the drawRect, then the view shows through and becomes transparent as I expected.
This is the only code I am using in the drawRect which just calls the superclass method:
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
}
What can be reason of this behavior?
It's quite likely that there is some under-the-hood shenanigans going on with UIView, and that the base class doesn't actually implement drawRect, or some sneaky optimisation is happening.
The documentation does say not to call super if you are directly overriding UIView, and it also says you don't need to implement drawRect if all you do is set a background colour or you populate the content in other ways:
The default implementation of this method does nothing. Subclasses that use native drawing technologies (such as Core Graphics and UIKit) to draw their view’s content should override this method and implement their drawing code there. You do not need to override this method if your view sets its content in other ways. For example, you do not need to override this method if your view just displays a background color or if your view sets its content directly using the underlying layer object. Similarly, you should not override this method if your view uses OpenGL ES to do its drawing.
And:
If you subclass UIView directly, your implementation of this method does not need to call super. However, if you are subclassing a different view class, you should call super at some point in your implementation.
It's therefore quite likely that by calling super you are losing something. You don't show any of your actual drawing code so its difficult to see where you might be going wrong with that, but as a starting point, don't call super if you've directly overridden UIView.
What are the differences between adding a view as a subView VS drawing the view in that view's drawRect method?.
I use both approaches, but I was wondering apart from the obvious such as, if you do in drawRect it will be a single View, as opposed as two views, or adding as a subview is just easier. Are there any specific situations where you should definitely use one over the other?
Overriding -drawRect: can be a good way to draw complex UITableViewCells. Having all of the subviews composited and drawn as one view helps table view scrolling performance immeasurably.
Having said that, I typically stick with the highest level API available and drop down to a lower level only if performance suffers.
Adding a subview is easier as you point out, and I really see this as no contest in 90% of cases. You should generally add a subview and let the libraries handle drawing of subviews in their correct position.
I only use -drawRect: to accomplish custom drawing within my view, but not to draw subviews, it creates unnecessary complexity. If you need a lot of performance, -drawRect: can help you there. Also, in the case of simple drawing, -drawRect: is very nice as opposed to making several subviews. But in general, it pays to just add a subview.
If in the future you decide you want these subviews to receive touch events or handle things interactively, it is more difficult to refactor your -drawRect: code.
My whole app uses touchesMoved for drawing (Coregraphics). Should I be calling [self setNeedsDisplay] from within touchesMoved instead of performing the drawing code in there? Would that stop some lag that I am experiencing? The only reason I didn't try this before posting is because it is going to take me a few hours to convert all drawing to within drawRect and I wanted to know if it would be more would efficient than drawing in touchesMoved?
Yes. You should always keep your drawing in drawRect and use setNeedsDisplay to trigger the actual drawing. This is key to the rendering of views in Cocoa Touch.
For example, if you didn't use this method, you could potentially have drawing code scattered around your class in multiple methods. In addition, this also ensures that your drawing code executes only once during a render cycle. Essentially, calling setNeedsDisplay triggers an invalidation flag that lets your UIView know to redraw itself. Without this, you could be performing extra drawing operations that aren't actually needed due to the render cycle.
You should not do drawing inside a UI callback. It will slow down or freeze the UI responsiveness, and you won't have the proper drawing context if you want to draw directly into a UIView.
Instead save, schedule or queue the information required for drawing for later, either into your own bitmap drawing context, or during the drawRect callback for that view.
Depending on the frame rate required, you many not even need to do a setNeedsDisplay on every touchesMoved event, but can queue the data and set a flag for an animation rate timer or CADisplayLink callback to do the setNeedsDisplay at a more constant rate (say only 15 or 30 frames per second). This will also help eliminate extra drawing operations.
I have a UIScrollView with a custom content view that uses drawRect to display its contents.
In my drawRect method I respect the passed CGRect parameter and only draw what's needed.
However, each time the drawRect is called it is passed the entire bounds of the view, even if it is several thousand pixels, and I'm worried about performance and memory use. Is there any way to make a UIScrollView limit this, or am I worrying too much over nothing?
Also, I've tried using CATiledLayer as the layer, and while this corrects the passed rect, it feels like I'm misusing the class. Also, the view still keeps all the pixels backed as far as I can tell. (Even if it doesn't draw some of them right away)
using CATiledLayer is probably the best option. I'm familiar with CATiledLayer as a concept, but never used it myself, so I'm not going to say anything about that. What I can say, is that if you subclass the UIScrollView and implement
layoutSubviews
you should be able to redraw the subviews toll-free with good performance, as long as you implement a construction using
CGRectIntersectsRect()
In which you can see if the current visible rect, in the case of a subclass
[self bounds]
intersects with the rect of the object you want to draw. if it doesn't, you can choose to ignore the object or even (if it is already on the scrollview) remove it from superview. if it does, you can place the object on superview.
again, CATiledLayer is a way better solution, but if you feel like you are misusing it, try the approach I described.
1.content view large than scrollview is true..
2.may be you should realize UiScrollViewDelegate's
scrollViewDidScroll
caculate content view 's rect that should be redrawed ,not the entire bounds .
I want to have a UIView subclass that has a border image, but I don't want or care about this 'new' frame/bounds around the border image itself.
What I wanted to do was just use drawRect and draw outside of the rect but all drawing is clipped and I don't see a way to not clip drawing outside of this context rect.
So now I have added a sublayer to the views layer, set [self clipsToBounds] on the view and override setFrame to control my sublayers frame and always keep it at the proper size (spilling over the views frame by 40px).
The problem with this is that setFrame on a uiview by default has no animation but seTFrame on a calayer does.
I cant just disable the animations on the calayers setFrame because if I were to call setFrame on the uiview inside a uiview animation block the calayer would still have its animation disabled.
The obvious solution is to look up the current animationDuration on the uiview animation and set a matching animation on the sublayer, but I don't know if this value is available. And even if it is, I'm afraid that calling an animation from within another animation is wrong.
Unfortunately the best solution is to not use a calayer at all and just add a uiview as a subview and draw into that just like I am drawing into my layer, and hope that with autoresizingMask set to height and width that everything will 'just work'. Just seems like unnecessary overhead for such a simple task.
My solution would be to override the initWithFrame: to add the surrounding border pixels and contain the content in a subview. It probably is unneccesary overhead but definietly the "cocoa" route. It's probably going to be easier in the end too since a subview structure will allow you to edit the content seperatly from the border so you dont have to redraw the border when you redraw the content. And keeping them seperate simply makes sense from a OOP perspective.
The clipsToBounds route is probably the easiest route besides the subview structure but managing the border and content in one drawing cycle and in one object will probably be a lot more work so it'll be worth the overhead.
Excuse any typos, typed this from my iPhone.