2010-11-22 10 views
10

Est-il possible de présenter un UIAlertView et de ne pas continuer à exécuter le reste du code dans cette méthode jusqu'à ce que l'utilisateur réponde à l'alerte?iphone UIAlertView Modal

Merci d'avance.

+2

L'arrêt du code n'empêcherait-il pas de répondre à l'utilisateur en appuyant sur le bouton? –

Répondre

20

Je suppose arrêter le code que vous vouliez dire était d'arrêter l'appareil pour exécuter le code suivant, vous avez écrit après la alertview

Pour cela il suffit de retirer votre code après votre alertview et de mettre ce code dans le délégué 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 
    } 
} 

Ne pas oublier d'inclure UIAlertViewDelegate dans le fichier .h

+4

Ugh. C'est triste, c'est la meilleure façon de gérer ça. "Oups, je viens juste de réaliser que je devrais m'assurer que l'utilisateur veut le faire avant d'exécuter le code Maintenant, laissez-moi réorganiser tout mon code ..." – GeneralMike

+0

Triste, mais plus asynchrone. – devios1

+0

Que faire si j'ai un paramètre pour 'yourFunction'? Comment puis-je le porter au délégué? – turzifer

1

Non, mais la solution facile consiste à diviser votre code au moment où vous présentez le UIAlertView - et à démarrer la seconde partie de votre méthode de délégation lorsque l'alerte est ignorée.

1

Je viens de tomber sur cette question pour MonoTouch, et d'essayer de trouver une réponse précédente a couru dans cette question ouverte.

Oui, c'est possible. L'exemple suivant en C# montre comment vous pouvez le faire avec MonoTouch, une version Objective-C de ceci devrait être facile à écrire:

Pour ce faire, vous pouvez exécuter manuellement le mainloop. Je n'ai pas réussi à arrêter le loop principal directement, donc je lance le loop principal pendant 0,5 seconde et j'attends que l'utilisateur réponde.

La fonction suivante montre comment vous pouvez mettre en œuvre une requête modale à l'approche ci-dessus:

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

Cela ne fonctionne apparemment plus avec iOS 5. – radiospiel

+0

Oui, c'est le cas. En l'utilisant ici. – Krumelur

+0

@Krumelur: Pourriez-vous poster le code que vous utilisez? Je ne connais pas C# et je ne suis pas très familier avec Objective-C, donc j'ai du mal à le convertir en quelque chose que je peux utiliser. – GeneralMike

9

Une réponse a déjà été accepté, mais je noterai pour tous ceux qui vient à travers cette question que, pendant que vous Vous ne devez pas l'utiliser pour la gestion normale des alertes. Dans certains cas, vous pouvez empêcher le chemin d'exécution actuel de continuer pendant la présentation d'une alerte. Pour ce faire, vous pouvez faire tourner la boucle d'exécution du thread principal.

J'utilise cette approche pour gérer les erreurs fatales que je veux présenter à l'utilisateur avant de planter. Dans un tel cas, quelque chose de catastrophique est arrivé, donc je ne veux pas revenir de la méthode qui a provoqué l'erreur qui pourrait permettre à un autre code d'être exécuté avec un état invalide et, par exemple, des données corrompues. Notez que cela n'empêchera pas le traitement des événements ou le blocage d'autres threads, mais étant donné que nous présentons une alerte qui reprend essentiellement l'interface, les événements doivent généralement être limités à cette alerte.

// 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. Je ne sais pas pourquoi d'autres réponses sont acceptées mais seulement la dose de votre solution fonctionne. –

+0

Semble que cela ne fonctionne pas sur XCode 5 – joan

1

Si le code qui doit attendre est tout dans la même méthode (ou peut être), les blocs peuvent être une autre option. J'ai créé une sous-classe UIAlertView pour gérer cela. Gardez juste à l'esprit que l'exécution continuera après l'appel [alerte]; cela vous donne juste un moyen de transmettre vos variables de pile sans créer de nouvelles variables de classe intermédiaires. De plus, si vous n'êtes pas familier avec les blocs Objective-C, vous devriez lire la documentation qui s'y rapporte; Il y a quelques pièges et une syntaxe étrange que vous devriez connaître.

ressemble à ceci:

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; 
} 

utilisé comme ceci:

__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]; 

Ce fut une mise en œuvre rapide, donc ne hésitez pas à trouver des bugs; mais vous avez l'idée.

+0

Quelque chose le long de ces lignes (en utilisant des blocs) est plus propre et ne nécessite pas de délégués partout. – Barry