Consejos sobre ModalForWindow de NSApp, ModalForWindow de NSAlert y ModalSession [cerrado]

Me llevó bastante experimentación aclarar cierta confusión sobre el lenguaje "ModalForWindow" de Objective-C y, posteriormente, cómo utilizar una sesión modal. Quizás los siguientes consejos le ahorren algo de tiempo a alguien:

(En caso de que sea nuevo en el concepto: cuando una ventana, generalmente un panel, ejecuta modal, evita que alguna otra parte de la aplicación responda hasta que se cierre).

"ModalForWindow" significa cosas diferentes en diferentes circunstancias. Si está utilizando loadNibNamed para mostrar un panel definido por un xib y desea que se ejecute modal, llame a esto una vez que se muestre:

// Make panelReviewImports modal, so that no other part of app will respond.
[[NSApplication sharedApplication] runModalForWindow:self.panelReviewImports];

y siga con esto en sus métodos de despido:

[[NSApplication sharedApplication] stopModal];

Pero para NSAlert, la "ventana" en beginSheetModalForWindow se refiere a la ventana a la que se enviará la alertaadjunto como una hoja, qué ventana se congelará hasta que se descarte la alerta. Pero elaplicación no se congelará; todas las demás ventanas permanecerán operativas. Si desea adjuntar una alerta como una hoja yademás congele el resto de la aplicación, siga el código beginSheet con una simple llamada a runModal y use el código de retorno explícitamente, así:

[alert beginSheetModalForWindow:self.window 
                  modalDelegate:self didEndSelector:@selector(abandonmentAlertDidEnd:returnCode:contextInfo:) 
                    contextInfo:nil];
NSInteger returnCode = [alert runModal];
[self abandonmentAlertDidEnd:alert returnCode:returnCode contextInfo:nil];

(Por supuesto, habrá implementado el abandonmentAlertDidEnd: returnCode: contextInfo: code como método de clase).

O, si desea que la alerta se ejecute como un panel centrado, llame a runModal por sí solo.

Suponga que desea ejecutar un panel modal, seguido de una alerta si el usuario envía una entrada no válida. Tendría que detener el modo antes de mostrar la alerta, después de lo cual, por alguna razón, otra llamada a runModalForWindow no funciona correctamente. Para este escenario, necesita unsesión modal:

1) Agregue una propiedad NSModalSession a su clase de controlador, porque modalSession debe ser accesible a través de múltiples métodos.

2) Una vez que haya mostrado el panel, llame a beginModalSessionForWindow para crear una instancia de modalSession:

self.modalSession = [[NSApplication sharedApplication] beginModalSessionForWindow:self.panelForInput];

3) Siga esto con un ciclo while que llama a runModalSession, interrumpiéndose cuando su retorno no sea igual a NSRunContinuesResponse:

while ([[NSApplication sharedApplication] runModalSession:self.modalSession] == NSRunContinuesResponse)
    continue;

El bucle se interrumpirá y la aplicación se liberará cuando el usuario haga clic en uno de los botones del panel. (Si escribe en el campo de texto del panel, la sesión modal quedará intacta).

4) En el manejo de su botón, si la entrada del usuario no es válida, llama a una alerta con runModal.

5) Inmediatamente debajo de la llamada de alerta, en el código que se ejecutará una vez que se descarte la alerta, coloque el mismo bucle while utilizado anteriormente. Se reanuda la sesión modal del panel.

6) En su manejo para cerrar el panel, ya sea después de una entrada válida o cancelar, llama a endModalSession, que, curiosamente, no es suficiente; También debe llamar a stopModal, aunque nunca haya llamado a runModalForWindow.

[[NSApplication sharedApplication] endModalSession:self.modalSession];
[[NSApplication sharedApplication] stopModal];
[self.panelForInput close];

Respuestas a la pregunta(1)

Su respuesta a la pregunta