2010-11-22 6 views
16

Estoy haciendo varios documentos locos dentro de una sola ventana con la arquitectura basada en documentos y estoy hecho en un 95%.¿Cómo inspeccionar la cadena de respuesta?

Tengo esta arquitectura de documentos de dos niveles, donde un documento principal se abre y configura la ventana, proporcionando una lista de documentos "secundarios". Cuando el usuario selecciona uno de los elementos secundarios, ese documento se abre con el mismo controlador de ventana y coloca un NSTextView en la ventana. La asociación de documentos del controlador de ventana se cambia para que el "punto editado" y el título de la ventana rastreen el documento seleccionado actualmente. Piense en un proyecto de Xcode y qué sucede cuando edita diferentes archivos en él.

Para poner el código en pseudo formulario, se invoca un método como este en el documento principal cuando se abre un documento secundario.

-(void)openChildDocumentWithURL:(NSURL *)documentURL { 
    // Don't open the same document multiple times 
    NSDocument *childDocument = [documentMapTable objectForKey:documentURL]; 
    if (childDocument == nil) { 
    childDocument = [[[MyDocument alloc] init] autorelease]; 
    // Use the same window controller 
    // (not as bad as it looks, AppKit swaps the window's document association for us) 
    [childDocument addWindowController:myWindowController]; 
    [childDocument readFromURL:documentURL ofType:@"Whatever" error:NULL]; 

    // Cache the document 
    [documentMapTable setObject:childDocument forKey:documentURL]; 
    } 

    // Make sure the window controller gets the document-association swapped if the doc came from our cache 
    [myWindowController setDocument:childDocument]; 

    // Swap the text views in 
    NSTextView *currentTextView = myCurrentTextView; 
    NSTextView *newTextView = [childDocument textView]; 
    [newTextView setFrame:[currentTextView frame]]; // Don't flicker  

    [splitView replaceSubview:currentTextView with:newTextView]; 

    if (currentTextView != newTextView) { 
    [currentTextView release]; 
    currentTextView = [newTextView retain]; 
    } 
} 

Esto funciona, y sé que el controlador de ventana tiene la asociación documento correcta en ningún momento desde el punto de cambio y el título siguen lo que estoy documento edición.

Sin embargo, cuando presiono guardar, (CMD + S, o Archivo -> Guardar/Guardar como) quiere guardar el documento principal, no el documento actual (según lo informado por [[NSDocumentController sharedDocumentController] currentDocument] y como lo indica el título de la ventana y cambiar el punto).

De la lectura de la documentación NSResponder, parece que la cadena debe ser la siguiente:

Vista actual -> Superview ( repetición) -> Ventana -> WindowController -> Documento -> DocumentController -> Aplicación.

No estoy seguro de cómo la arquitectura basada en documentos está configurando la cadena de respuesta (es decir, cómo está colocando NSDocument y NSDocumentController en la cadena) así que me gustaría depurarla, pero no estoy seguro de dónde buscar. ¿Cómo accedo a la cadena de respuesta en un momento dado?

Respuesta

38

Puede iterar sobre la cadena de respuesta utilizando el método nextResponder de NSResponder. Para su ejemplo, debe ser capaz de comenzar con la vista actual y, a continuación, en repetidas ocasiones imprimir el resultado de la llamada en un bucle como este:

NSResponder *responder = currentView; 
while ((responder = [responder nextResponder])) { 
    NSLog(@"%@", responder); 
} 
+0

Gracias, no sé cómo no se me había ocurrido eso, estaba tan concentrado en la idea de buscar directamente toda la pila de una vez. – d11wtq

6

Aquí es otra versión para los usuarios Swift:

func printResponderChain(_ responder: UIResponder?) { 
    guard let responder = responder else { return; } 

    print(responder) 
    printResponderChain(responder.next) 
} 

Simplemente llámelo consigo mismo para imprimir la cadena de respuesta desde su auto.

printResponderChain(self) 
3

También puede agregar una categoría para UIResponder clase con el método apropiado que es posible ser utilizado por cualquier subclase de UIResponder.

@interface UIResponder (Inspect) 

- (void)inspectResponderChain; // show responder chain including self 

@end 

@implementation UIResponder (Inspect) 

- (void)inspectResponderChain 
{ 
    UIResponder *x = self; 
    do { 
     NSLog(@"%@", x); 
    }while ((x = [x nextResponder])); 
} 
@end 

de lo que puede utilizar este método en algún lugar de código como el siguiente ejemplo:

- (void)viewDidLoad { 
    ... 
    UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; 
    [self.view addSubview:myView]; 
    [myView inspectResponderChain]; // UIView is a subclass of UIResponder 
    ... 
} 
2

Swift 3:

func printResponderChain(from responder: UIResponder?) { 
    var responder = responder 
    while let r = responder { 
     print(r) 
     responder = r.next 
    } 
} 


printResponderChain(from: view) 
1

voy a mejorar un poco en la categoría de respuesta en respuesta, mediante el uso de un método de clase que se siente más "utilizable" cuando se depura (no es necesario dividir una vista específica o lo que sea).

El código es para Cocoa pero debería ser fácilmente portátil para UIKit.

@interface NSResponder (Inspect) 

+ (void)inspectResponderChain; 

@end 

@implementation NSResponder (Inspect) 

+ (void)inspectResponderChain 
{ 
    NSWindow *mainWindow = [NSApplication sharedApplication].mainWindow; 

    NSLog(@"Responder chain:"); 
    NSResponder *responder = mainWindow.firstResponder; 
    do 
    { 
    NSLog(@"\t%@", [responder debugDescription]); 
    } 
    while ((responder = [responder nextResponder])); 
} 

@end 
Cuestiones relacionadas