Chenya Zhang
Chenya Zhang

Reputation: 463

dismissViewController completion handler not called

Try to use the code from the first answer in the link (by Kampai): How to use UIAlertController to replace UIActionSheet?

However, the completion handler is not even called in my code.

The alert action sheet can be dismissed after pressing both buttons but nothing inside the completion handler works. Any idea what might be the problem? I'm new to using completion handler and have tried to find answers online, but few have the same problem as mine.

- (IBAction)takePhotoButtonPressed:(UIButton *)sender {
pressedButtonTagNumber = sender.tag;

UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];

[actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {

    // Cancel button tappped
    [self dismissViewControllerAnimated:YES completion:^{
    }];
}]];

[actionSheet addAction:[UIAlertAction actionWithTitle:@"Take a Photo" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
    NSLog(@"!");
    // Take a Photo button tapped
    [self dismissViewControllerAnimated:YES completion:^{
        NSLog(@"0"); // NOT CALLED
        // Initialize UIImagePickerController
        UIImagePickerController *takePhotoImagePickerController = [[UIImagePickerController alloc] init];            takePhotoImagePickerController.delegate = self;
        takePhotoImagePickerController.allowsEditing = YES;
        NSLog(@"1");
        // Check and assign image source
        if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
            NSLog(@"2");
            UIAlertController *noCameraErrorSheet = [UIAlertController alertControllerWithTitle:@"Camera is not available" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
            [noCameraErrorSheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
                // Cancel button tappped
                [self dismissViewControllerAnimated:YES completion:^{
                }];
            }]];
        } else {
            takePhotoImagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
            // Present UIImagePickerController
            [self presentViewController:takePhotoImagePickerController animated:YES completion:NULL];
        }

    }];
}]];

Solution:

@Paulw11 solution works great:

1) No need to dismissViewController for UIAlertController. 2) Cannot call a new UIAlertController if the one wraps it is dismissing (obviously). 3) Better to check and disable the button in advance.

UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];

[actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
}]];

UIAlertAction *takePhotoActionButton = [UIAlertAction actionWithTitle:@"Take Photo" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
    [self takePhoto];
}];
UIAlertAction *uploadPhotoActionButton = [UIAlertAction actionWithTitle:@"Upload from Library" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
    [self uploadPhoto];
}];

// Disable take a photo button if source not available
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
    [takePhotoActionButton setEnabled:FALSE];
}
// Disable upload a photo button if source not available
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
    [uploadPhotoActionButton setEnabled:FALSE];
}

[actionSheet addAction:takePhotoActionButton];
[actionSheet addAction:uploadPhotoActionButton];

// Present action sheet.
[self presentViewController:actionSheet animated:YES completion:nil];

Upvotes: 2

Views: 2753

Answers (1)

Paulw11
Paulw11

Reputation: 114975

You don't need to call dismissViewController:animated: from within the action handler to remove the alert. UIAlertController calls this to dismiss itself prior to invoking the action handler code.

In your action handler you simply need to execute whatever should be done when that action is selected:

In this case:

  • In your cancel action you don't need to do anything
  • In your "take a photo" action you take a photo

Also, from a user experience point of view, it may be better to disable the "take a photo" or present an alert as soon as they select it rather than issuing an alert after they have attempted to take a photo; in other words indicate the problem earlier rather than later

Upvotes: 5

Related Questions