objective-c uialertview ios8 uiactionsheet uialertcontroller

objective c - Mostrar UIAlertController de la clase UIView/NSObject



objective-c uialertview (9)

Tengo una working iOS application Para support iOS8 , estoy reemplazando UIAlertView/UIActionSheet with UIAlertController .

Problema:
Para visualizar UIAlertController, necesito el método presentViewController de la clase UIViewController.
Pero UIAlertView se muestra desde clases que se inherited de UIView or NSObject ,
No puedo obtener el método [self presentViewController...] por razones obvias.

Mi trabajo :
Intenté que rootViewController formara la ventana actual y visualice UIAlertController.

[[[UIApplication sharedApplication] keyWindow].rootViewController presentViewController ...]

pero tengo algunos problemas de rotación, como si mi controlador de vista actual no tiene soporte de rotación, rotará si UIAlertController está abierto.

Pregunta:
¿Alguien se enfrentó al mismo problema y tiene una solución segura?
Si es así, por favor dame un ejemplo o dame alguna guía


Parece que actualmente (antes de iOS8) está activando una vista de alerta desde el objeto de visualización. Esa es una práctica bastante mala, ya que en general las alertas deben activarse a partir de acciones y lógica. Y ese código debería vivir en controladores.

Le sugiero que refactorice su código actual para mover la lógica que activa la alerta al controlador correcto, y luego puede actualizar fácilmente a iOS 8 utilizando self como controlador.

Si, en cambio, llama a la alerta desde un objeto externo, pase el controlador al método que llama a la alerta. En algún lugar aguas arriba debe tener conocimiento del controlador.


Tuve una situación en la que una subvista contiene un botón para descartarla. Presento una alerta para confirmar la acción. Envía un mensaje al delegado, que es el controlador de vista que contiene la subvista, para eliminar la subvista

Originalmente presenté UIAlertView desde una UIView. Refactorizando para UIAlertController, ya que el UIAlertController no puede presentarse como una lata UIAlertView, se me ocurrió lo siguiente (en Swift, traducido fácilmente a ObjC):

Agregue un protocolo a la subvista:

protocol MySubviewDelegate { // called when user taps subview/delete button // or, you could call it from a gesture handler, etc. func displayAlert(alert : UIAlertController) // called when user confirms delete from the alert controller func shouldRemoveSubview(sender : AnyObject) }

Agregue un delegado para la subvista y agregue un controlador para el toque de botón / gesto:

class MySubview : UIView { var subviewDelegate : MySubviewDelegate! ... func handleTap(sender : AnyObject) { // set up the alert controller here var alert = UIAlertController(title: "Confirm Delete", message: "This action is permanent. Do you wish to continue?", preferredStyle: UIAlertControllerStyle.Alert) // Cancel action // nil handler means "no action if Cancel button selected" alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)) // Confirm action alert.addAction(UIAlertAction(title: "Confirm", style: UIAlertActionStyle.Default, handler: { (action : UIAlertAction!) -> Void in // call delegate method to perform confirmed action, - i.e. remove self.subviewDelegate.shouldRemoveSubview(self) })) // call delegate method to display alert controller // send alert object to delegate self.subviewDelegate.displayAlert(alert) } }

Establezca el UIViewController llamante como el delegado de la subvista, por ejemplo, en su método viewDidLoad () e incluya los métodos de protocolo:

class viewController : UIViewController, MySubviewDelegate { override func viewDidLoad() { super.viewDidLoad() self.subviewDelegate = self ... } func displayAlert(alert : UIAlertController) { presentViewController(alert, animated: true, completion: nil) } func shouldRemoveSubview(sender : AnyObject) { // cast as UIView / MySubview subclass var subview = sender as MySubview // remove the subview / perform the desired action subview.removeFromSuperview() ... } ... }

Esto evita la necesidad de encontrar el controlador de vista superior, o pasar referencias para ver los controladores a las subvistas (que no sean una relación objeto / delegado).


La mejor solución para UIView clases de UIView está debajo

C objetivo

UIViewController *currentTopVC = [self currentTopViewController]; currentTopVC.presentViewController......... - (UIViewController *)currentTopViewController { UIViewController *topVC = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; while (topVC.presentedViewController) { topVC = topVC.presentedViewController; } return topVC; }

Rápido

var topVC = UIApplication.sharedApplication().keyWindow?.rootViewController while((topVC!.presentedViewController) != nil){ topVC = topVC!.presentedViewController } topVC?.presentViewController........


Mi solución está abajo:

Rápido

class alert { func msg(message: String, title: String = "") { let alertView = UIAlertController(title: title, message: message, preferredStyle: .Alert) alertView.addAction(UIAlertAction(title: "Done", style: .Default, handler: nil)) UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alertView, animated: true, completion: nil) } }

Aquí está el uso de muestra:

let Alert = alert() Alert.msg("My alert (without title)") Alert.msg("This is my alert", title: "Warning!")


En Swift 3:

UIApplication.shared.keyWindow?.rootViewController?.present(alertView, animated: true, completion: nil)


He tenido este problema. Ver my SO aquí para el código para obtener el controlador de vista superior con el que presentar otro controlador de vista.

Estoy de acuerdo en que, en la mayoría de los casos, es una mala práctica presentar un controlador de vista desde un objeto que no es un controlador de vista, pero a veces es OBLIGATORIO.


Resolví un problema esencialmente similar hoy. Al igual que Jageen , me encontré con una situación en la que quería presentar un UIAlertController pero desde una clase que no sea UIViewController. En mi caso, quería que apareciera una alerta cuando se ejecuta el bloque de falla de una solicitud HTTP.

Esto es lo que usé y, a diferencia de nuestro amigo aquí, funcionó perfectamente para mí.

UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(errorAlert, animated: true, completion: nil)


En general, las alertas se deben manejar en el controlador de vista. Aquí hay un ejemplo del código requerido:

Swift 3

private func displayError(message: String) { let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert) let okayAction = UIAlertAction(title: "Okay", style: .default, handler: nil) alertController.addAction(okayAction) present(alertController, animated: true, completion: nil) }


Para la pantalla UIAlertController en NSObject Class, use el siguiente código.

UIAlertController * popup = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet]; UIAlertAction* cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) { [popup dismissViewControllerAnimated:YES completion:nil]; }]; [popup addAction:cancel]; UIViewController *rootViewController = [[Helper shareInstance] topViewController]; [rootViewController presentViewController:popup animated:YES completion:nil];

// Ponga debajo del método en su clase Global Helper.

- (UIViewController *)topViewController { return [self topViewController:[UIApplication sharedApplication].keyWindow.rootViewController]; } - (UIViewController *)topViewController:(UIViewController *)rootViewController { if (rootViewController.presentedViewController == nil) { return rootViewController; } if ([rootViewController.presentedViewController isMemberOfClass:[UINavigationController class]]) { UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController; UIViewController *lastViewController = [[navigationController viewControllers] lastObject]; return [self topViewController:lastViewController]; } UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController; return [self topViewController:presentedViewController]; }