drawRect causes slow scrolling even though it is not being called - iphone

In my app I have a scrollView with about 20 subviews in it. Each of these subviews has a drawRect method that at the moment looks like this:
- (void)drawRect:(CGRect)rect
{
NSLog(#"drawRect called");
}
When the subviews are added, drawRect is called, however when I scroll it is very slow even though drawRect is not called again.
If I remove the implementation for drawRect, then scrolling is completely normal. Even if I can't get rid of the slow scrolling, is there an alternative to drawRect which I could use instead?

Why are you calling drawRect if it is only logging that it was called? If that is it's only purpose for you, then just don't call it. In fact, I believe when you first create a class that inherits from UIView that has the drawRect method in it, it is commented out and above the commented out drawRect method, it says something along the lines of "Do not call this method if it does not do any drawing on screen as it takes up a significant amount of memory". Basically, don't call it in your case.
Hope this helps.

You could try assigning pre-drawn CGImages to the contents of each custom view's CALayer, before the view first appears. This may be faster than using a drawRect to customize a view's appearance.

Related

Subclassed UIView shows black background if drawRect: is overridden

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.

UIView subclass creating its own UIButtons

I have subclassed UIView so I can draw some lines in it. In this UIView are a whole bunch of buttons which I decided to create as a method that drawRect calls after the lines are drawn. It works but sometimes only part of the button renders. If i remove the button creation and instead add the UIButton in the subclassed UIViews parent it works fine.
Is doing things like adding subviews in drawRect method a big no no or should I not do it all together in UIView?
yea that's a pretty big no no. drawRect is for adding stuff with CG, not views. It gets called repeatedly and unpredictably. Adding them in initWithFrame should be pretty safe though.

UITextField not showing when added as subview

I'm making an OpenGL ES application and I am trying to work out how to incorporate parts of the UIKit GUI over the view with the OpenGL ES working on it.
In the init method of the EAGLView class I have this to setup the UITextField:
add_name_field = [[UITextField alloc] initWithFrame: CGRectMake(10, 10, [UIScreen mainScreen].bounds.size.width, 50)];
Somewhere in the drawRect method where everything is rendered and processed for the game I have:
[add_name_field becomeFirstResponder];
[self insertSubview: add_name_field atIndex:0];
I can confirm this code is called because I used NSLog to test that but when it is run the text field does not show over the game's OpenGL view. If I put the code in the init method, the text field shows properly with the keyboard at te beginning of the game.
So how do I get it to work in the drawRect method?
Thank you for any answer. I will write some code for the delegate in the meantime.
THank you for all the other answers but I found the solution.
It was a simple solution. I simply moved the addSubView method to the initialisation of the EAGLView class. The keyboard wont show until I make the text field the first responder. When I'm finished with it, I can simply clear the text and make the EAGLView class the first responder again and that hides it all again.
This way I can simply use the keyboard to get text input for my game, displaying text when typing and hiding it afterwards.
I assume you're in a UIViewController subclass, with the code above? If so, then instead of
[self insertSubview: add_name_field atIndex:0];
do:
[self.view addSubview:add_name_field];
The important part is, you're calling this method on self.view rather than self. Adding subviews is a VIEW function, not a View CONTROLLER function.
insertSubview:atIndex: ought to work too (if called on the right object), but addSubview: will stick it on top of the view no matter what else is there, so it's a bit cleaner.
Add your text subview outside of drawRect. drawRect is for rendering that one view, and may or may not ignore drawing any other views (such as your text view), depending on how the view stack is rendered.
Is there any reason to have it done in the drawRect method? You said that it works fine in the init method, so why not have it there?
As for why it doesn't work, I don't exactly know OpenGL views but, assuming they work just like regular UIViews, you probably shouldn't be adding other UIViews in the drawRect function. UIViews don't get shown & drawn immediately; they have to wait till the runloop tells them to draw. Likely what happens is that when your superview's drawRect finishes, it assumes all its subviews have finished drawing and doesn't realized that your newly added textfield didn't get a chance to. What you could try is calling setNeedsDisplay on your textfield.

UIScrollView draws unused part of view

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 .

Drawing a CGLayer outside the method drawRect: faster?

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.