iphone - uiimagepickercontrollerdelegate - Presentar un controlador de vista modal inmediatamente después de descartar otro
uiimagepickercontrollerdelegate swift 4 (8)
Al igual que otras cosas animadas, dismissModalViewControllerAnimated
no se bloquea hasta que desaparece el controlador de vista. En cambio, "inicia" la destitución del controlador de vista. Es posible que deba utilizar una devolución de llamada en viewDidDisappear
del controlador modal 1 que llama a algo como modalViewControllerDisappeared
en el controlador de vista principal. En ese método, presenta el controlador modal 2. De lo contrario, lo que Robot K dijo.
Estoy descartando un controlador de vista modal y presentando inmediatamente otro, pero esto último nunca ocurre. Aquí está el código:
[self dismissModalViewControllerAnimated:YES]; UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.delegate = self; picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum; [self presentModalViewController:picker animated:YES];
El primer VC modal se desliza hacia abajo, pero el nuevo picker
nunca aparece. ¿Alguna idea de lo que está pasando?
Aquí está mi enfoque que parece funcionar muy bien en iOS 10. Mi circunstancia es ligeramente diferente, pero debería funcionar para la mayoría de las situaciones. Presento el viewController inicial como un popover que requiere un viewController modal para ser presentado inmediatamente.
Primero, en viewDidLoad de viewDidLoad
simplemente oculte su vista:
view.isHidden = true
Luego, en viewWillAppear
, presente viewController modal, no anulado y des-ocultar la vista al finalizar:
present(yourModalViewController, animated: false) { [unowned self]
self.view.isHidden = false
}
Es probable que desee controlar su estado con un Bool
para que las llamadas subsiguientes a viewWillAppear
no vuelvan a presentar el modal, pero se entiende la idea.
En Swift:
- Use dismissViewController para descartar la primera vista presentada.
- Utilice cerrar el bloque de finalización de ViewController para llamar a una función en mainVC. Esa función debería llamar al segundo VC.
Su despedir ViewController debe verse así:
var presentingVC_Delegate: mainLists_PopoverDelegation!
@IBAction fund button_Pressed (sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: { finished in
self.presentingVC_Delegate.presentOtherVC()
print("DismissVC completion block says hello")
})
}
Donde el principalVC casas que presentanOtherVC:
func presentSettingsVC () {
self.performSegueWithIdentifier("present_OtherVC", sender: nil)
}
En este caso, creo delegar al controlador de vista principal de devolución de llamada para mostrar el segundo controlador de vista modal.
Protocolo de definición del controlador de vista padre:
@protocol ParentViewControllerDelegate
- (void)showModalTwo;
@end
Implemente este protocolo en el controlador de vista principal para mostrar el segundo controlador de vista modal y crear el delegado @property id<ParentViewControllerDelegate> delegate;
en el primer controlador de vista modal.
Muestra el primer controlador de vista modal desde el controlador de vista padre:
TheFirstModalViewController *controller = ...
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];
...
En viewDidDisappear:
método del primer controlador de vista modal, simplemente llame a delegate.showModalTwo:
para mostrar la segunda vista modal desde el controlador de vista principal.
Espero que esto ayude.
Lo que sucede es que el controlador de vista elimina su referencia al controlador de vista modal una vez que finaliza la animación de desactivación, que ocurre después de que se llama este código, por lo que no cree que tenga un controlador de vista nuevo para presentarse de forma modal.
La forma en que he lidiado con esto es establecer un didDismissModalVC
ivar a YES
después de llamar a dismissModalViewController
. Luego, en mi método viewDidAppear:
compruebo el valor de ivar y presento el nuevo controlador de vista modal. (Recordando también establecer el valor de nuevo en NO
por lo que no me quedo atascado eternamente, descartando los controladores de vista modal).
Actualización de agosto de 2012:
iOS 5 y posteriores han introducido API más seguras para hacer las cosas después de que los modales se hayan animado dentro / fuera de lugar usando bloques de finalización:
[self presentViewController:myModalVC animated:YES completion:^{}];
[self dismissViewControllerAnimated:YES completion:^{}];
Pre-ago 2012 Respuesta:
Encontré un problema similar cuando descarté el modal uno y luego presenté el modal dos en rápida sucesión. Algunas veces el modal dos se mostraría después de que se descartara el modal y algunas veces el modal dos no aparecería en absoluto y eso me entristeció.
Parece una condición de carrera para mí ...
Poniendo un segundo retraso 1+ en la persona que llama del método que presentó el modal dos, showModalTwo
, hizo que aparecieran modal dos cada vez después de que se descartara el modal uno:
- (void)didDismissModalOne {
[self performSelector:@selector(showModalTwo:)
withObject:someNumber
afterDelay:1.0f];
}
Esto confirmó la sospecha de que había algún tipo de condición de carrera entre el despido del modal uno y la presentación del modal dos. Sin embargo, demorar a la persona que llama es poco elegante y no garantizaba que la condición de carrera no reapareciera en otras circunstancias.
El problema
Resulta que UIViewController
s tiene una propiedad pública, modalViewController
, que se configura cuando presentModalViewController:animated:
se dismissModalViewControllerAnimated:
se dismissModalViewControllerAnimated:
cuando se llama a dismissModalViewControllerAnimated:
se llama. El inconveniente es que no se destruye de forma síncrona, por lo que es posible crear una carrera entre la eliminación del antiguo valor de modalViewController
y la configuración de un nuevo valor de la siguiente manera.
- Presente uno modal.
myViewController.modalViewController
ahora apunta a uno modal - Descartar modal uno.
myViewController.modalViewController
ha iniciado el proceso en segundo plano para eliminarmyViewController.modalViewController
, peromyViewController.modalViewController
aún apunta a uno modal - Presente modal dos,
myViewController.modalViewController]
ahora apunta a modal dos - La devolución de llamada del sistema se dispara, estableciendo
myViewController.modalViewController
ennil
, esto interrumpe el proceso de animar modal dos y el resultado es que el usuario nunca lo ve.
La carrera comienza en el paso 2 y se manifiesta en el paso 4.
La solución
Mi solución fue poner una condición de guardia en el método que presentaba el modal dos para asegurar que myViewControoler.modalViewController
era nil
antes de intentar presentar el modal dos.
-(void)showModalTwo:(NSNumber *)aParameter {
if (self.modalViewController) {
[self performSelector:@selector(showModalTwo:)
withObject:aParameter
afterDelay:0.1f];
return;
}
// You can now present the second modal safely.
}
Trabajado como un encanto. Una solución más elegante puede incluir un tiempo de espera.
Post script
Realmente no me gustó el aspecto de votación de esta solución. @Nimrod sugiere, en la respuesta aceptada a esta pregunta, que puede iniciar de manera segura la presentación del modal dos del método viewDidDisappear:
del modal uno. Me gustó el sonido de este enfoque orientado a eventos, pero después de hacer una implementación completa en mi caso de uso confirmé que la condición de carrera persistió al presentar el modal dos usando una devolución de llamada dentro de viewDidDisappear:
La única manera de estar absolutamente seguro de que se presentará el modal dos es realizar una encuesta dentro del controlador de vista padre hasta que esté absolutamente seguro de que self.modalViewController
es nil
. Entonces, y solo entonces, es "seguro" sacar el modal dos.
[self dismissModalViewControllerAnimated:NO];
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
[self presentModalViewController:picker animated:YES];
[self dismissViewControllerAnimated:YES completion:^{
//Present the new MVC
}];
Nota: Disponible iOS 5.0 en adelante.