2010-07-08 10 views
7

[Esta es mi primera publicación aquí (pero he navegado muchas veces, gracias a todos por un sitio muy útil). Si estoy cometiendo algún gran pecado con esta publicación, por favor perdóneme y apúnteme en la dirección correcta.]cómo obtener CGContextRef desde UIView o UIWindow para depurar el método de dibujo externo?

Estoy intentando depurar algún código de inicio complicado en mi aplicación de iPhone; Realmente necesito dibujar algunas imágenes para que la depuración sea más perspicaz, y para reducir radicalmente el tedio de depuración.

El estado que necesito dibujar realmente no existe como un objeto modelo; es algo transitorio durante la inicialización. En especial, quiero poder dibujar un poco de estado a la vez, en lugar de hacerlo todo en una imagen grande (para ayudarme a ver qué componentes están correctos/incorrectos). En mi caso, hay muchas cosas potencialmente superpuestas y una sola imagen no puede mostrar claramente lo que está sucediendo.

Crear una vista estática que atraiga a la pantalla usando la arquitectura de dibujo normal podría ser posible, si agrego un modo de depuración especial y controles adicionales para navegar/resaltar/dibujar componentes, pero requerirá un montón de andamios antinaturales , y no es, IMO, la forma correcta de solucionar mi problema.

Por lo tanto, lo que espero que hacer es:

  1. obtener o crear un drenaje adecuado CGContextRef
  2. en ella
  3. ras a pantalla inmediatamente
  4. espera por alguna entrada del usuario, que no implica UIEvents
  5. repita 1-4 tantas veces

El elemento 4 parece ser casi imposible (¿hay alguna manera de obtener algo como la simple E/S de consola C o C++ que funciona en el iPhone o en el simulador de iPhone?), Así que me he rendido por el momento; Me conformaré con usar el depurador Xcode para parar entre las operaciones de dibujo.

Pero más interesante es cómo obtener un CGContextRef fuera de un método de dibujo UIView, en el que dibujar el resultado de depuración. El almacenamiento en caché de un contexto previamente válido, incluso si fuera posible en mi situación (no es posible, ya que estoy depurando al inicio de la aplicación), parece no funcionar. Parece como si los contextos pudieran crearse de nuevo para cada operación de dibujo, lo cual me parece que genera muchos gastos generales; Hubiera asumido una ventana de UI, y tal vez una UIView, guardada y podría proporcionar una referencia a un contexto de dibujo apropiado. Parece que debo estar equivocado (pero si no, ¿cómo obtengo un contexto de una vista o ventana? No he encontrado ningún método para esto).

Entonces, si debo crear un contexto de dibujo, ¿cómo lo hago? Supongo que realmente no entiendo exactamente qué es lo que está ligado por un contexto: ¿en qué medida conoce y se vincula a algún dispositivo de visualización de salida específico? ¿Cómo controlo a qué porción de la pantalla se asigna un contexto? Parece haber muy pocas formas de crear un contexto, y no parecen proporcionar ese control. UIGraphicsBeginImageContext parece ser la única rutina que podría ayudarme, y no veo cómo será útil crear y dibujar en uno, solo para producir un CGImage como resultado; ¿Cómo obtendría la imagen resultante en la pantalla?

No me sorprenderá descubrir que estoy confundido acerca de algunas cosas básicas relacionadas con los contextos CG. Afortunadamente, esta pregunta no es tan básica y obvia que molestaré a todos los que la lean, pero si me he perdido completamente la documentación correcta, apreciaría mucho algunos consejos.

Gracias por su ancho de banda mental, y cualquier ayuda.-jar

+0

adición Menor: CGBitmapContextCreate no parece que me ayude más que UIGraphicsBeginImageContext/UIGraphicsEndImageContext hacer. Toda mi lectura sobre Quartz 2D en iPhone (o incluso Mac OS X) sugiere que no hay forma de dibujar en la pantalla fuera del método drawRect de UIView. Supongo que esto se relaciona con la optimización del rendimiento, ocultando la complejidad de la creación de CGContext o alentando a los desarrolladores a dibujar en la forma aprobada por la arquitectura. Todavía espero que me esté perdiendo algo. – jarFlooby

+0

una vez que haya creado su contexto, puede guardarlo como una imagen, y luego si (depurar) [self presentModalViewController: specialDebugViewController]; que contiene el UIImageView ... no llevará mucho andamiaje como dices. –

+0

Todo el dibujo parece estar mediado por un 'CALayer'. Una capa tiene un contexto asociado (y viceversa; 'CAContext' tiene una propiedad' layer'). 'UIWindow' tiene una instancia' CAContextImpl' en su '_layerContext' ivar. Tratar de dibujar en un contexto de este tipo podría hacer que dibujes un contexto * inválido *. No veo ningún equivalente a los métodos de escritorio '-lockFocus' /' -lockFocusIfCanDraw' que te permitirían forzar el contexto de una ventana para que sea válida. –

Respuesta

5

Tiene razón porque no puede dibujar directamente en la pantalla. Una vez dicho esto, se puede indicar a un UIView que actualice a voluntad si llama al [view setNeedsDisplay]. Si anula - (void)drawRect:(CGRect)rect, se invocará al actualizar. Mi sugerencia para su problema es subclase UIView, exponer su estado de depuración en esta clase, y cuando actualice el estado, forzar una actualización. Si está actualizando el estado a una frecuencia alta, debe usar CADisplayLink para vincular la actualización de la vista a la actualización de la pantalla. Si llama al [view setNeedsDisplay] varias veces antes de volver a dibujar la vista, no tendrá importancia.

Por ejemplo:

#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 

NOTA: Debe añadir al QuartzCore.framework para ejecutar este

+0

'frameInterval' es en realidad un' NSInteger' por lo que establecer con '1.0f' puede llevar a alguien más a leer el código a pensar que es un' float'. Lo mejor para la claridad es usar '1' en su lugar. –

+0

Tiene razón, hecho –

Cuestiones relacionadas