Question

I have the following code:

-(IBAction)showAlertView:(id)sender{

alertView = [[UIAlertView alloc] initWithTitle:@"Atualizando" message:@"\n"delegate:self cancelButtonTitle:nil otherButtonTitles:nil];

spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];   
spinner.center = CGPointMake(139.5, 75.5); // .5 so it doesn't blur
[alertView addSubview:spinner];
[spinner startAnimating];
[alertView show]; 
}


-(IBAction)getContacts:(id)sender {

[self showAlertView:(id)self];

ABAddressBookRef addressBook = ABAddressBookCreate( );
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook );
CFIndex nPeople = ABAddressBookGetPersonCount( addressBook );

I want to show the alert before the rest of the IBAction begins, but im seeing the alertView only at the end of the IBAction. What am I doing wrong?

EDIT: i have:

-(IBAction)getContacts:(id)sender {

// display the alert view
[self showAlertView:self];

// do the synchronous operation on a different queue
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

ABAddressBookRef addressBook = ABAddressBookCreate( );
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook );
CFIndex nPeople = ABAddressBookGetPersonCount( addressBook );

....

if ([contact length] == 8) {

            NSString *first = (NSString*)ABRecordCopyValue(person, kABPersonFirstNameProperty);
            NSString *last = (NSString*)ABRecordCopyValue(person, kABPersonLastNameProperty);
            NSString *phone = contact;
            ContactInfo *user1 = [[ContactInfo alloc] init];
            user1.first = first;
            user1.last = last;
            user1.phone = phone;
            user1.person = person;
            user1.phoneIdx = j;
            user1.book = addressBook;
            NSLog(@"phone is %@", phone);
            [secondViewController.users addObject:user1];
        }
        ABRecordSetValue(person, kABPersonPhoneProperty, mutablePhones, &error);
    }
}
bool didSave = ABAddressBookSave(addressBook, &error);
if(!didSave){
    NSLog(@"error!");
}
dispatch_async(dispatch_get_main_queue(), ^{
    [self hideAlertView]; // or however you want to do it
});

UIAlertView *alertAlmost = [[UIAlertView alloc] initWithTitle:@"Quase Pronto" message:@"Os seguintes contatos não tem código de área. Porfavor, selecione os contatos que você deseja adicionar o digito 9 e pressione Ok (caso não queira adicionar em nenhum, pressione Ok) " delegate:self cancelButtonTitle:@"Ok!" otherButtonTitles:nil];
[alertAlmost show];

[self presentViewController: secondViewController animated:YES completion: NULL];
 });
}

I want the alert to dismiss, and then i can call the table view. Any sugestions?

Was it helpful?

Solution

Showing a UIAlertView is done asynchronously, so if you call showAlertView: at the top of the method, it'll show the alert view and then return immediately after, then do the rest of your method.

If you want the rest of your method to happen after the alert view is dismissed, you need to add yourself as the alert view's delegate, then implement the method

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex

and do the rest of your stuff in there.


Edit: Okay, I think I get your problem. You're doing some time consuming synchronous operation on the main queue and that's blocking it so that the alert view isn't displayed until later.

You should move the time consuming operation to a different queue like so:

-(IBAction)getContacts:(id)sender {
    // display the alert view
    [self showAlertView:self];

    // do the synchronous operation on a different queue
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        ABAddressBookRef addressBook = ABAddressBookCreate( );
        CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook );
        CFIndex nPeople = ABAddressBookGetPersonCount( addressBook );

        // once this operation has finished, you can hide the alert view like so:
        dispatch_async(dispatch_get_main_queue(), ^{
            [self hideAlertView]; // or however you want to do it
        });
    });
}

OTHER TIPS

You need to do the rest of the code in your "getContacts:" when your alert is dismissed. Set a delegate on your UIAlertView of "self" (the view controller showing the alert) and then do the "addressBook" stuff when the user clicks the button to dismiss the alert.

For example, implement the UIAlertViewDelegate method alertView:clickedButtonAtIndex: and do your address book stuff in there (I linked the documentation for you).

I think you're saying that you want to popup an alert, like a progress indicator, and while that alert is up, you want to start your other process. Currently, you request to have the alert shown immediately, but as the other answers have said, that call is asynchronous, and the UI thread does not manage to get the alert displayed before starting on the other work.

You could try this:

-(IBAction)getContacts:(id)sender {

    [self showAlertView:(id)self];
    [self performSelectorInBackground: @selector(initAddressBook) withObject: nil];
}

-(void)initAddressBook {
    ABAddressBookRef addressBook = ABAddressBookCreate( );
    CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook );
    CFIndex nPeople = ABAddressBookGetPersonCount( addressBook );
}

If there's some problem with running the address book work in the background, you might even be able to give the UI thread enough time to get the alert posted with something like this:

-(IBAction)getContacts:(id)sender {

    [self showAlertView:(id)self];
    [self performSelector: @selector(initAddressBook) withObject: nil afterDelay: 0.1f];
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top