UIActivityViewController crashing on iPad with sourceView or barButtonItem
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)
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, 2022Comments
-
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:
-
amitsbajaj over 8 yearsHi @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 over 8 yearsNo problem! I don't think you can, maybe you could use a UiPopoverController instead?
-
amitsbajaj over 8 yearsThanks 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 over 8 yearsOhhh, i think you have to displays the activityViewController inside a UIPopoverController. I've updated my answer with some code.
-
amitsbajaj over 8 yearsThat worked like a charm! Thanks so much for your help on this JDx - really appreciate it! :)