Thursday, June 7, 2012

CODE SNIPPET: Modal UIAlertView for Password Entry

After a few days, I finally managed to solve a problem that has been bothering me for a while. In iOS, UIAlertView is a non-modal way of displaying a message. This works fine for most circumstances, as majority of code can easily be broken up to accommodate the UIAlertView delegate methods, however sometimes you just need to sit down and block all further instructions until you get an answer.

Getting a password on the fly is one of those times.

This snippet was put together as a utility function, independent of class, implementation and delegate methods.  Feel free to use it and adapt it as you see fit, and it would be nice if you'd toss a line of credit in there somewhere.

NSString * DisplayModalPasswordEntry (NSString *szTitle, NSString *szMessage)
{
    // First, initialize the alert with our desired title and message
    // The delegate is nil because we will not be allowing delegate methods
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:szTitle 
                                                message:szMessage
                                                delegate:nil 
                                                cancelButtonTitle:@"Cancel" 
                                                otherButtonTitles:@"OK", 
                                                nil];

    // Make the entry secure
    [alert setAlertViewStyle:UIAlertViewStyleSecureTextInput];
    
    // Show our alert
    [alert show];

    // NSRunLoop will handle our blocking without explicitly blocking
    // NSDate will provide us with a condition for the NSRunLoop
    // UITextField and UIButton are for editing purposes during the loop
    NSRunLoop *rl = [NSRunLoop currentRunLoop];
    NSDate *d;
    UITextField *pTextField = [alert textFieldAtIndex:0];
    UIButton *pOKButton;
    
    // This loop goes through the subviews in alert looking for our button
    for (UIView *view in alert.subviews) 
    {
        // If it's a button
        if([view isKindOfClass:[UIButton class]]) 
            // And if it's the button we're looking for
            if ([((UIButton *)view).titleLabel.text isEqualToString:@"OK"])
            {
                pOKButton = (UIButton *)view;
                break;
            }
    }
    
    // So long as the alert is active
    while ([alert isVisible]) 
    {
        // NSDate init returns 'now' 
        d = [[NSDate alloc] init];
        
        // runUntil will run once and stop, since 'now' is 'then
        [rl runUntilDate:d];
        
        // Since we've disallowed delegate methods, we handle our button status here
        if ([pTextField.text length] == 0)
            pOKButton.enabled = NO;
        else 
            pOKButton.enabled = YES;
    }
    
    // Once we break out of our loop, we return whatever they entered
    return pTextField.text;
}

No comments:

Post a Comment