I have seen many posts about this problem but didn't get an answer. I have a controller which view is added to the main window. The controller's view has a subview which has a drawRect. The problem is that this function is never called even if I call [self setNeedsDisplay].
Thanks
It is -(void)drawRect:(CGRect)rect right? Make sure the method signature is correct, and you don't omit the rect argument even if you don't use it.
-setNeedsDisplay should be called the the subview, not self.
Also, -setNeedsDisplay won't call -drawRect: immediately. It only flushes the graphics cache so that -drawRect: is forced to be called in the next update of the frame.
Related
If a Single View app is created, with a FooView that subclasses UIView, and do a
NSLog(#"hello");
in drawRect, then it is printed.
And if I create a subclass of CALayer called CoolLayer, and add this method to FooView.m:
+(Class) layerClass {
return [CoolLayer class];
}
and at the end of FooView.m's drawRect, do a
NSLog(#"layer's class is %#", self.layer.class);
then CoolLayer is printed. So now the view's underlaying layer is CoolLayer.
But when the following is added to CoolLayer.m:
-(void) display {
}
which is the method that is automatically called to redraw the layer (similar to drawRect), then no NSLog whatsoever was printed. It might be that the app went into an infinite loop. (even my touchesBegan that prints out NSLog messages is not printing). If a breakpoint is set at display, it will stop there once but when I continue the program, it will never arrive at display again. What is wrong with this and how can it be fixed?
The layer's display method will not be called again unless the layer is dirty, i.e. set to need a redisplay. This is usually a good thing, and is why you don't see the method being called more than once.
Also, the normal implementation of display will call the drawInContext: method. Since you override this in your subclass, the drawRect: method of the view is never called. You need to either replicate the standard behavior of CALayer, or call the superclass' display method in your own implementation.
That does not sound like an infinite loop. If you were in an infinite loop your app would freeze, and after a few seconds the springboard app would kill it for being unresponsive.
Call setNeedsDisplay or setNeedsDisplayInRect on your layer to make it "dirty" and require drawing again. Note that you don't want to call setNeedsDisplay any more than you have to, because it takes a lot of work to re-render the layer and push it's contents onto the screen. Only display when something has changed
You're not seeing an infinite loop here. If you were, as Duncan points out, you'd eventually crash either due to the watchdog timer or from an infinite recursion that would be immediately obvious in the stack trace you'd see in the debugger.
If you put an NSLog into your UIView's -drawRect: method, then override its default layer class with your own custom CALayer that does its own drawing, your UIView's -drawRect: would no longer be called. Drawing would now be handled by your custom backing layer.
As described in the "Providing CALayer Content by Subclassing" subsection of the Core Animation Programming Guide, you typically override -display in your CALayer if you want to somehow customize the contents CGImageRef for your layer. Normally, you'll be overriding -drawInContext: if you want to render custom Quartz drawing within your CALayer. Making your overridden -display method totally blank, and not writing anything to the contents property, is not standard behavior, so I'm not surprised that you're seeing odd results from doing that.
Based on your series of recent questions, I highly recommend you stop and spend some time reading the Core Animation Programming Guide and looking at some sample code involving CALayers before proceeding further.
I'm experiencing that the drawRect method is called after the modalViewController has shown. Is it possible call the drawRect method before, so there won't be any delay?
Best regards
Sebastian Søndergaard
No, the drawRect method is called at the time of drawing. If your drawing code is doing too much however, you can pre-calculate it and put in in a CGLayerRef for example. Then your drawRect method can just paint the layer into the context.
You can do calculations on a background thread (carefully), then send it back to the main thread and call setNeedsDisplay on the view, if your main thread is choppy.
I have an app which is targeted to iOS 4 and above.I have a custom view, which is having
1.Scroll view
2.Custom drawing inside scroll view.
Now when my app is resuming from background,I want to refresh/reload this scroll view.
setNeedsDisplay is not working here as it usually meant for loading custom drawings and here I want to reload my scroll view contents.
Thanks in advance.
If I understand your question correctly, setNeedsDisplay does not work for you in this case because you need to "reload" the data that the UIScrollView handles before doing the redraw.
If this is right, I would define a method in your controller that does the reloading part; then, I would call this method from applicationDidEnterForeground or applicationWillEnterForeground; the reload method will need to call setNeedsDisplay after reloading the data.
I am sorry if this answer seems very generic to you. If you explain more or post some code, I can try and be more specific.
Have you tried redraw inside viewDidAppear?
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[yourScrollView setNeedsDisplay];
}
setNeedDisplay calls the drawRect which is repainting operation. If you want to refresh the content only simply create one method in viewController and notify this method using performSelectorOnMainThread if you created new thread whenever thread complete (or you receive Data).
My object a sub class of NSObject has CALayer instance variable. I use it for drawing and caching content with its delegate set to my object.
But for some reason drawLayer:inContext: method NEVER gets called. Whereas actionForLayer:forKey: delegate method does get called implying the delegate is getting set properly with layer.delegate = self in the object's init method.
Any suggestions on what is preventing my layer drawing method drawLayer:inContext: from getting called ?
I am called the [layer setNeedDisplay] often. So I guess it is some fundamental error.
drawLayer:inContext: won't get called if your frame is CGRectZero or offscreen. Also, if your CALayer isn't attached to an existing onscreen layer, it will never draw, no matter how many times you call setNeedsDisplay
Implement an empty drawRect:
- (void)drawRect:(CGRect)rect {
}
Taken from the ZoomingPDFViewer project:-
UIView uses the existence of -drawRect: to determine if it should
allow its CALayer to be invalidated, which would then lead to the
layer creating a backing store and -drawLayer:inContext: being
called. By implementing an empty -drawRect: method, we allow UIKit
to continue to implement this logic, while doing our real drawing work
inside of -drawLayer:inContext:
The layer object's setNeedsDisplay must be called. Simply adding the layer as a sublayer does not do that for you. Got this from Ray Wenderlich's CALayer tutorial.
If you're eventually using the CALayer with a UIView then the delegate must be the view object itself:
From the iOS CALayer documentation:
"In iOS, if the layer is associated with a UIView object, this property must be set to the view that owns the layer."
If you have a multi-threaded app where background processing drives the need to update the CALayer, you must call setNeedsDisplay in the main thread
I have a UIView subclass that I manipulate a lot of graphics on based on touches. All the [self setNeedsDisplay] calls seem to be fine.
However, I used an instance variable pointer to my same UIView subclass instance, and then tried manipulating it and then calling [UIViewSubClass setNeedsDisplay] from another UIView class, and DrawRect is never being called. Are there restrictions to where you can call setNeedsDisplay from?
(This method is called when a button is clicked on another UIView subclass. The method is being called, but not DrawRect)
-(IBAction)loadGrid2;
{
tempSoundArray = musicGridView1.soundArray;
[musicGridView1.soundArray setButtonArrayToNull];
[musicGridView1 setNeedsDisplay];
musicGridView1.soundArray = tempSoundArray;
NSLog(#"loadGrid2 was called");
}
drawRect: will only be called when it makes sense; ie, the view must be visible, onscreen, and dirty. Is your drawRect: ever called? It should be called when the view is first brought onscreen as well.
To add to Ben:
This most likely means that you have problems elsewhere. Your pointer may not be nil or otherwise invalid or the view may not be added to the hierarchy properly.
You may want to consider not handling this type behavior within the view and instead in the view controller. Control behavior and save presentation state in the view controller and don't subclass the view classes. It will simplify your code with less "pointer passing". This will also make it easier to debug this type of problem.
If you feel your view controller is getting bloated, consider splitting the responsibilities up among multiple view controllers.