Search code examples
iosobjective-cipaduiwebviewuiactivityviewcontroller

UIActivityViewController crashing on iPad with sourceView or barButtonItem


I have come across what looks like a situation that most people face when trying to present a UIActivityViewController on the iPad; it is crashing with:

Terminating app due to uncaught exception 'NSGenericException', reason: 'UIPopoverPresentationController (<_UIAlertControllerActionSheetRegularPresentationController: 0x7fc4f2d87d00>) should have a non-nil sourceView or barButtonItem set before the presentation occurs.

Here's my code:

- (void)shareLeaflet
{
    NSString *forwardedString = [[NSString alloc] initWithFormat:@"Check out this leaflet\n\n %@ \n\nself.theURLToShare];
    UIActivityViewController *activityViewController = nil;

    if (IDIOM == IPAD)
    {
        NSLog(@"iPad");
        activityViewController.popoverPresentationController.sourceView = self.view;
//        activityViewController.popoverPresentationController.sourceRect = self.frame;
        [self presentViewController:activityViewController
                           animated:YES
                         completion:nil];

    }
    else
    {
        NSLog(@"iPhone");
        activityViewController = [[UIActivityViewController alloc] initWithActivityItems:[NSArray arrayWithObjects:forwardedString, nil] applicationActivities:nil];
        [self presentViewController:activityViewController animated:YES completion:nil];


    }

In my viewDidLoad, I have:

UIBarButtonItem *composeButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self                                    action:@selector(shareLeaflet)];

    self.navigationItem.rightBarButtonItem = composeButton;
}

This view is a UIPageViewController which is showcasing some images and when the user hits the share button, I'm expecting the iOS 8 style share sheet to popup. This is exactly what happens on the iPhone, but on the iPad, it continues to crash. That led me to Stack Overflow, but none of the questions (crash on showing UIPopOverPresentationController, iOS Crash: Terminating app due to uncaught exception reason: UIPopoverPresentationController should have a non-nil sourceView, UIWebViewTerminating app due to UIPopoverPresentationController, ios8 iPad uiwebview crashes while displaying popover when user taps drop down list HTML select tag, etc) work for me.

I have tried all of the solutions in there and I just quite get what is required with this.

This is what I'm trying to achieve:

enter image description here Any thoughts on this would be really appreciated.


Solution

  • You aren't initialising the activityViewController on iPad so it will always be nil.

    Try:

    - (void)shareLeaflet
    {
        NSString *forwardedString = [[NSString alloc] initWithFormat:@"Check out this leaflet\n\n %@ \n\nself.theURLToShare];
        UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:[NSArray arrayWithObjects:forwardedString, nil] applicationActivities:nil];
    
        if (IDIOM == IPAD)
        {
            NSLog(@"iPad");
            activityViewController.popoverPresentationController.sourceView = self.view;
    //        activityViewController.popoverPresentationController.sourceRect = self.frame;
            [self presentViewController:activityViewController
                               animated:YES
                             completion:nil];
        }
        else
        {
            NSLog(@"iPhone");
            [self presentViewController:activityViewController 
                              animated:YES 
                            completion:nil];
        }
    

    And then to display it like in the image: (_shareBarButton is the UIBarButtonItem that you want the popover to display from)

    - (void)shareLeaflet
        {
            NSString *forwardedString = [[NSString alloc] initWithFormat:@"Check out this leaflet\n\n %@ \n\nself.theURLToShare];
            UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:[NSArray arrayWithObjects:forwardedString, nil] applicationActivities:nil];
    
            if (IDIOM == IPAD)
            {
                NSLog(@"iPad");
                activityViewController.popoverPresentationController.sourceView = self.view;
        //        activityViewController.popoverPresentationController.sourceRect = self.frame;
    
               _popover = [[UIPopoverController alloc] initWithContentViewController:activityViewController];
               _popover.delegate = self;
               [_popover presentPopoverFromBarButtonItem:_shareBarButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
            }
            else
            {
                NSLog(@"iPhone");
                [self presentViewController:activityViewController 
                                  animated:YES 
                                completion:nil];
            }