2010-11-22 10 views
10

¿Es posible presentar un UIAlertView y no continuar ejecutando el resto del código en ese método hasta que el usuario responda a la alerta?iphone UIAlertView Modal

Gracias de antemano.

+2

¿No parando el código significaría que no podría responder al usuario presionando el botón? –

Respuesta

20

supongo que detener el código que quería decir era para detener el dispositivo para ejecutar el siguiente código que ha escrito después de la alertview

Para ello basta con retirar su código después de su alertview y poner ese código en el delegado alertview

-(void) yourFunction 
{ 
    //Some code 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:@"Your Message" delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil]; 
      [alert show]; 
      [alert release]; 
    //Remove all your code from here put it in the delegate of alertview 
} 
-(void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex: (NSInteger)buttonIndex 
{ 
if(buttonIndex==0) 
    { 
     //Code that will run after you press ok button 
    } 
} 

No se olvide de incluir UIAlertViewDelegate en el archivo .h

+4

Ugh. Un poco triste esta es la mejor manera de lidiar con esto. "Oops, me acabo de dar cuenta de que debo asegurarme de que el usuario quiera hacer esto antes de ejecutar el código. Ahora déjame reorganizar todo mi código ..." – GeneralMike

+0

Triste, pero más asíncrono. – devios1

+0

¿Qué ocurre si tengo un parámetro para 'yourFunction'? ¿Cómo puedo llevarlo al delegado? – turzifer

1

No, pero la solución más fácil es dividir el código en el punto donde se presenta el UIAlertView, y comenzar la segunda parte desde el método de delegado cuando se descarta la alerta.

1

me encontré con esta pregunta para MonoTouch, y tratando de encontrar una respuesta anterior se topó con esta pregunta abierta.

Sí, es posible. El siguiente ejemplo en C# muestra cómo puede hacerlo con MonoTouch, una versión de Objective-C de esto debería ser fácil de escribir:

Para hacer esto, lo que puede hacer es ejecutar manualmente el lazo principal. No he logrado detener el mainloop directamente, así que en lugar de eso corro el mainloop por 0.5 segundos y espero hasta que el usuario responda.

La siguiente función muestra cómo se puede implementar una consulta modal con el enfoque anterior:

int WaitForClick() 
{ 
    int clicked = -1; 
    var x = new UIAlertView ("Title", "Message", null, "Cancel", "OK", "Perhaps"); 
    x.Show(); 
    bool done = false; 
    x.Clicked += (sender, buttonArgs) => { 
     Console.WriteLine ("User clicked on {0}", buttonArgs.ButtonIndex); 
    clicked = buttonArgs.ButtonIndex; 
    };  
    while (clicked == -1){ 
     NSRunLoop.Current.RunUntil (NSDate.FromTimeIntervalSinceNow (0.5)); 
     Console.WriteLine ("Waiting for another 0.5 seconds"); 
    } 

    Console.WriteLine ("The user clicked {0}", clicked); 
    return clicked; 
} 
+1

Esto aparentemente ya no funciona con iOS 5. – radiospiel

+0

Sí, lo hace. Utilizándolo aquí. – Krumelur

+0

@Krumelur: ¿Podría publicar el código que está utilizando? No estoy familiarizado con C# y apenas estoy familiarizado con Objective-C, así que estoy teniendo problemas para convertir esto en algo que pueda usar. – GeneralMike

9

Una respuesta ya ha sido aceptado, pero voy a destacar para cualquier persona que viene a través de esta pregunta que, si bien se no debe usar esto para el manejo normal de alertas, en determinadas circunstancias, es posible que desee evitar que la ruta de ejecución actual continúe mientras se está presentando una alerta. Para hacerlo, puede girar en el ciclo de ejecución para el hilo principal.

Utilizo este enfoque para manejar los errores fatales que quiero presentar al usuario antes de colisionar. En tal caso, ha ocurrido algo catastrófico, por lo que no deseo regresar del método que causó el error que podría permitir que otro código se ejecute con un estado no válido y, por ejemplo, datos corruptos.

Tenga en cuenta que esto no evitará que los eventos se procesen o bloquee la ejecución de otros subprocesos, pero como estamos presentando una alerta que esencialmente toma la interfaz, los eventos generalmente se deben limitar a esa alerta.

// Present a message to the user and crash 
-(void)crashNicely { 

    // create an alert 
    UIAlertView *alert = ...; 

    // become the alert delegate 
    alert.delegate = self; 

    // display your alert first 
    [alert show]; 

    // spin in the run loop forever, your alert delegate will still be invoked 
    while(TRUE) [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]]; 

    // this line will never be reached 
    NSLog(@"Don't run me, and don't return."); 

} 

// Alert view delegate 
- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex { 
    abort(); // crash here 
} 
+0

thx. No sé por qué se acepta otra respuesta, pero solo funciona la dosis de solución. –

+0

Parece que no funciona en XCode 5 – joan

1

Si el código que debe esperar está en el mismo método (o puede serlo), los bloques pueden ser otra opción. Creé una subclase UIAlertView para manejar esto. Solo tenga en cuenta que la ejecución continuará más allá de la llamada [alerta]; esto solo te da una forma de pasar tus variables de pila sin hacer nuevas variables de clase intermedias. Además, si aún no está familiarizado con los bloques Objective-C, debe leer la documentación que contiene; hay algunos inconvenientes y alguna sintaxis extraña que deberías conocer.

es algo como esto:

typedef void (^MyAlertResult)(NSInteger clickedButtonIndex); 

@interface MyBlockAlert : UIAlertView 
{ 
    MyAlertResult finishedBlock; 
} 
- (void) showWithCompletionBlock:(MyAlertResult)block; 
... 

- (void) showWithCompletionBlock:(MyAlertResult)block 
{ 
    self.delegate = self; 
    finishedBlock = [block copy]; 
    [self show]; 
} 

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex 
{ 
    finishedBlock(buttonIndex); 
    [finishedBlock release]; 
    finishedBlock = nil; 
} 

utilizarse como esto:

__block NSArray* arrayOfDeletes; // set to something 
MyBlockAlert* areYouSureAlert = [[MyBlockAlert alloc] initWithTitle:@"Really delete?" message:@"Message" delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles:@"Delete", nil]; 

[arrayOfDeletes retain]; // Make sure retain count is +1 

[areYouSureAlert showWithCompletionBlock: 
^(NSInteger clickedButtonIndex) 
{ 
    if (clickedButtonIndex == 1) 
    { 
     // Clicked okay, perform delete 
    } 
    [arrayOfDeletes release]; 
}]; 
[areYouSureAlert release]; 

Esta fue una implementación rápida, por lo que se sienten libres para encontrar cualquier error; Pero se entiende la idea.

+0

Algo en esta línea (usando bloques) es más limpio y no requiere delegados por todos lados. – Barry