UIActivityViewController crashing on iPad with sourceView or barButtonItem

14,562

Solution 1

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];
        }

Solution 2

You can just set the popoverPresentationController's barButtonItem for iPad, for example:

let activityViewController = UIActivityViewController(activityItems: ["Hello, world!", urlString], applicationActivities: nil)

if UIDevice.current.userInterfaceIdiom == .pad {
    activityViewController.popoverPresentationController?.barButtonItem = barButtonItem
}

self.present(activityViewController, animated: true)

Solution 3

best solve for iPad & iPhone iOS 14.4

let urlstring = "https://apps.apple.com/ae/app/"
let text = "some text for your app"
let url = NSURL(string: urlstring)
let textToShare = [url!,text] as [Any]
let activityViewController = UIActivityViewController(activityItems: textToShare as [Any], applicationActivities: nil)
    
activityViewController.excludedActivityTypes = [ UIActivity.ActivityType.airDrop, UIActivity.ActivityType.postToFacebook ,UIActivity.ActivityType.postToFlickr,UIActivity.ActivityType.postToTwitter,UIActivity.ActivityType.postToVimeo,UIActivity.ActivityType.mail,UIActivity.ActivityType.addToReadingList]

activityViewController.popoverPresentationController?.sourceView = self.view
activityViewController.popoverPresentationController?.sourceRect = view.bounds
activityViewController.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.down
UIApplication.shared.windows.first?.rootViewController?.present(activityViewController, animated: true, completion: nil)
Share:
14,562
amitsbajaj
Author by

amitsbajaj

Mobile Security Consultant and an upcoming iOS Developer. I have completed the CS193P Stanford course (through iTunes) and am ready to progress to my first app.

Updated on June 05, 2022

Comments

  • amitsbajaj
    amitsbajaj almost 2 years

    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.

  • amitsbajaj
    amitsbajaj over 8 years
    Hi @JDx - ah man, that was easy! Sorry for the easy question there, that worked like a charm! Thank you! But just to ask a follow up question - can I control which side the popup comes from? Right now, it's coming from the top left of the screen, but the button is actually on the top right.
  • Jordan Davies
    Jordan Davies over 8 years
    No problem! I don't think you can, maybe you could use a UiPopoverController instead?
  • amitsbajaj
    amitsbajaj over 8 years
    Thanks JD - I'm just trying to activate the UIActivityViewController, like the iOS 8/9 Share sheet. I have just updated the question to include an image from Safari on the iPad - it comes straight under that button but mine is appearing on the left which is weird
  • Jordan Davies
    Jordan Davies over 8 years
    Ohhh, i think you have to displays the activityViewController inside a UIPopoverController. I've updated my answer with some code.
  • amitsbajaj
    amitsbajaj over 8 years
    That worked like a charm! Thanks so much for your help on this JDx - really appreciate it! :)