Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to obtain CGContextRef from UIView or UIWindow for debugging outside draw method?

[This is my first post here (but I've browsed answers many times; thanks to all for a very useful site). If I'm committing any great sins with this post, please forgive me and point me in the right direction.]

I am trying to debug some complicated startup code in my iPhone application; I really need to draw some images to make debugging more insightful, and to radically reduce debug tedium.

The state I need to draw does not really exist as a model object; it is somewhat transient during initialization. I especially want to be able to draw one bit of state at a time, rather than all of it in one big image (to help me see which components are right/wrong). In my case, there is lots of potentially overlapping stuff and a single image cannot easily, clearly display what's going on.

Creating a static view which draws to the screen using the normal drawing architecture might be possible, if I add a special debug mode, and additional controls to navigate / highlight / draw components, but it will require a lot of unnatural scaffolding, and is not, IMO, the right way to debug my problem.

So, what I hope to do is:

  1. get or create an appropriate CGContextRef
  2. draw in it
  3. flush it to screen immediately
  4. wait for some input from the user, that doesn't involve UIEvents
  5. repeat 1-4 many times

Item 4 seems to be almost impossible (is there a way to get something like simple C or C++ console I/O working in the iPhone, or the iPhone simulator?), so I've given up on it for now; I'll settle for just using the Xcode debugger to stop between drawing operations.

But more of interest is how to get a CGContextRef outside of a UIView draw method, in which to draw the debug output. Caching a previously valid context, even if it were possible in my situation (not possible, since I'm debugging at app startup), appears not to work. It seems as if contexts may be created anew for each drawing operation, which strikes me as incurring a lot of overhead; I would have assumed a UIWindow, and maybe a UIView, saved and could provide a reference to an appropriate drawing context. Seems I must be wrong (but if not, how do I get a context from a view or window? I've found no methods for this).

So, if I must create a drawing context, how do I do it? I guess I really don't quite understand what exactly is bound together by a context: to what extent does it know about, and bind to, some specific display output device? How do I control what portion of the screen a context maps to? There seem to be very few ways to create a context, and they don't seem to provide such control. UIGraphicsBeginImageContext seems to be the only routine that might help me, and I don't see how creating and drawing into one, only to produce a CGImage as a result will be useful; how would I get the resulting image onto the screen?

I won't be surprised to find I'm confused about some basic stuff related to CG contexts. Hopefully, this question isn't so basic and obvious that I'll be annoying everyone who reads it, but if I've completely missed the right documentation, I'd be very appreciative of a few pointers.

Thanks for your mental bandwidth, and any help. -jar

like image 474
jarFlooby Avatar asked Jul 08 '10 10:07

jarFlooby


1 Answers

You are correct in that you cannot draw directly to the screen. That being said, a UIView can be instructed to refresh at will if you call [view setNeedsDisplay]. If you override - (void)drawRect:(CGRect)rect, this will be called upon refresh. My suggestion for your problem is to subclass UIView, expose your debug state on this class, and when you update the state, force a refresh. If you are updating state at a high frequency, you should use CADisplayLink to tie the view refresh to the display refresh. If you call [view setNeedsDisplay] multiple times before the view redrawn it will not matter.

For example:

#import "QuartzTestView.h"
#import <QuartzCore/QuartzCore.h>

@interface QuartzTestView()

- (void)refreshView:(CADisplayLink*)displayLink;

@end


@implementation QuartzTestView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code

        CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawView:)];
        [displayLink setFrameInterval:1];
        [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    }
    return self;
}

- (void)refreshView:(CADisplayLink*)displayLink {
    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect
{
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    // do updates

}

@end

NOTE: You must add the QuartzCore.framework to run this

like image 91
Stuart Carnie Avatar answered Sep 28 '22 18:09

Stuart Carnie