Ventana modal personalizado con Bloque de Terminación Handler
-
22-09-2019 - |
Pregunta
Estoy atascado!
Estoy intentando crear un diálogo modal personalizado. Me gustaría que para llevar a cabo de manera similar a la NSSavePanel usando un bloque como un manejador de finalización.
He copiado sólo los fragmentos importantes que consideren necesarias.
@implementation ModalWindowController
- (void)makeKeyAndOrderFront:(id)sender
modalToWindow:(NSWindow*)window
sourceRect:(NSRect)rect
completionHandler:(void (^)(NSInteger result))handler {
_handler = [handler retain];
session = [NSApp beginModalSessionForWindow:[self window]];
[[NSApplication sharedApplication] runModalSession:session];
[[self window] makeKeyAndOrderFrontCentered:self expandingFromFrame:rect];
}
- (IBAction)okButtonPressed:(id)sender {
[[self window] orderOut:self];
_handler(NSOKButton);
[NSApp endModalSession:session];
}
@end
Ahora puede llamar a esto utilizando el código:
[self.modalWindowController makeKeyAndOrderFront:self
modalToWindow:[[self view] window]
sourceRect:sr
completionHandler:^(NSInteger result) {
NSLog(@"Inside Block");
if ( result == NSOKButton ) {
// do something interesting here
}
}];
NSLog(@"Errg");
Todo va bien, sin embargo, después de que el método makeKeyAndOrderFront: modalToWindow: sourceRect: completionHandler: ha completado que no bloquea el hilo, por lo que "errg" se imprimirá aunque el usuario no ha seleccionado "OK" o "cancelar". La ventana modal se muestra en este punto, donde se ejecuta entonces el usuario hace clic en OK y el bloque _handler. Sin embargo, si estoy tratando de acceder a las variables locales en el bloque, y la aplicación se bloquea, ya que todo ha limpiado ya.
¿Cuál es el mejor enfoque para bloquear el hilo principal de la makeKeyAndOrderFront: ... método? Es este el enfoque correcto para la implementación de un controlador de finalización utilizando bloques?
Solución
Su línea
_handler=[handler retain];
debería ser
_handler=[handler copy];
Esto debería resolver su problema, que las variables locales se han ido antes de que el controlador de finalización se llama.
[handler copy]
se encarga de las variables locales que se refiere el bloque, por lo que las variables locales no desaparecen incluso después de que el flujo del programa salió del método en la que hizo el bloque.
Recuerde los siguientes hechos:
- Las capturas instancia del bloque de las variables locales que se refiere el interior del bloque.
- Sin embargo, la instancia de bloque está en la pila. Que va a desaparecer incluso lo retienen, cuando el flujo del programa salir de la
{...}
ámbito en el que se crea el bloque. - Por lo tanto, es necesario que
copy
, no sóloretain
, si desea utilizar los datos después, como lo están haciendo aquí.Copy
ing automáticamenteretain
s todas las variables objeto local que se refiere a partir del bloque. - Es necesario
release
una vez que haya terminado con él. Se desasigna la memoria para el propio bloque, y envía el mensajerelease
al objeto local de las variables que se refiere. Si utiliza GC, usted no tiene que preocuparse por esto, sin embargo.
Para entender más detalles de la cuadra, he encontrado el artículo aquí por Mike Ash muy útiles.