Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix run-time error using UIAlertController

I have this code sitting in a UIVIewController (XCode 6.1, iOS 8.1.1):

[UIAlertController showActionSheetInViewController:self
                         withTitle:@"Test Action Sheet"
                         message:NSLocalizedString(@"Are you sure you want to delete ALL appointments?",nil)
                         cancelButtonTitle:@"Cancel"
                         destructiveButtonTitle:@"Yes"
                         otherButtonTitles:@[@"No"]  //  same as Cancel
                         tapBlock:^(UIAlertController *controller, UIAlertAction *action, NSInteger buttonIndex){
                              if (buttonIndex == UIAlertControllerBlocksCancelButtonIndex) {
                                 NSLog(@"Cancel Tapped");
                             } else if (buttonIndex == UIAlertControllerBlocksDestructiveButtonIndex) {
                                 NSLog(@"Delete Tapped");
                             } else if (buttonIndex >= UIAlertControllerBlocksFirstOtherButtonIndex) {
                                 NSLog(@"Other Action Index %ld", (long)buttonIndex - UIAlertControllerBlocksFirstOtherButtonIndex);
                             }
                         }];

When I run it, I get this run-time error:

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Your application has presented a UIAlertController (<UIAlertController: 0x7fdfe3324f00>) of style UIAlertControllerStyleActionSheet. The modalPresentationStyle of a UIAlertController with this style is UIModalPresentationPopover. You must provide location information for this popover through the alert controller's popoverPresentationController. You must provide either a sourceView and sourceRect or a barButtonItem. If this information is not known when you present the alert controller, you may provide it in the UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation.'

What do I need to do to make this work? (I have looked at SO and Google and found nothing specific). I appreciate any help I can get on this...

UPDATE I re-wrote it without the 3rd-party code; added this code, and now it works!

    UIAlertController * view=   [UIAlertController
                             alertControllerWithTitle:@"My Title"
                             message:@"Select your Choice"
                             preferredStyle:UIAlertControllerStyleActionSheet];

UIAlertAction* ok = [UIAlertAction
                     actionWithTitle:@"OK"
                     style:UIAlertActionStyleDefault
                     handler:^(UIAlertAction * action)
                     {
                         //Do some thing here
                         [view dismissViewControllerAnimated:YES completion:nil];

                     }];
UIAlertAction* cancel = [UIAlertAction
                         actionWithTitle:@"Cancel"
                         style:UIAlertActionStyleDefault
                         handler:^(UIAlertAction * action)
                         {
                             [view dismissViewControllerAnimated:YES completion:nil];

                         }];


[view addAction:ok];
[view addAction:cancel];

view.popoverPresentationController.sourceView = self.view;
view.popoverPresentationController.sourceRect = CGRectMake(self.view.bounds.size.width / 2.0, self.view.bounds.size.height / 2.0, 1.0, 1.0);
[self presentViewController: view animated:YES completion:nil];
like image 203
SpokaneDude Avatar asked Dec 29 '14 00:12

SpokaneDude


2 Answers

The error message you received appeared because you ran iPhone code on an iPad. For use on an iPad, you have to set the alertController's popoverPresentationController. The source rectangle can be generated without the sloppy dimension calculations, too. Below, is a complete method, showing how you would encounter the code upon pressing a button. After setting up the AlertController the way you want, you get its popoverPresentationController and set it up for use with the iPad. In the method below, the button what was pressed is the sender. So we cast the sender back to that button, then use the button to set the rectangle. No messy dimensions need calculating. Now, if you run the code on the iPad, the popover will not display the Cancel button, (which does appear on the iPhone). That is by design. If you view the Apple UIPopoverController documentation, you see that the popover is cancelled by tapping outside of it.

- (IBAction)showImagePickerButtonTapped:(id)sender;
{
    BOOL isCameraAvailable = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera];
    BOOL isPhotoLibraryAvailable = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary];

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

    [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];

    if (isCameraAvailable) {
        [alertController addAction:[UIAlertAction actionWithTitle:@"Camera" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
            [self _showImagePickerWithSourceType:UIImagePickerControllerSourceTypeCamera];
        }]];
    }

    if (isPhotoLibraryAvailable) {
        [alertController addAction:[UIAlertAction actionWithTitle:@"Photo Library" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
            [self _showImagePickerWithSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
        }]];
    }

    // The following lines are needed for use with the iPad.
    UIPopoverPresentationController *alertPopoverPresentationController = alertController.popoverPresentationController;
    UIButton *imagePickerButton = (UIButton*)sender;
    alertPopoverPresentationController.sourceRect = imagePickerButton.frame;
    alertPopoverPresentationController.sourceView = self.view;

    [self showDetailViewController:alertController sender:sender];
}
like image 72
Jerry Frost Avatar answered Nov 01 '22 17:11

Jerry Frost


There's precious little information to go on here...

It appears you're using https://github.com/ryanmaxwell/UIAlertController-Blocks, not the standard UIAlertController, in which case the exception suggests changes that the version of the code you're using doesn't cover yet or a use case that requires extra work on your part.

I've never used this 3rd-party code but a quick check doesn't show any obvious "do this" in the docs. My initial recommendation would be to implement the delegate method on the view in question and give it what it wants - the location at which to present the popover.

like image 29
Brad Brighton Avatar answered Nov 01 '22 15:11

Brad Brighton