9

When a UIActivityViewController is called on the iPhone in this app, it works perfectly, but when called on a iPad, the app crashes. Below is the code I used:

func shareButtonPress() {

    //when the share button is pressed, default share phrase is added, cropped image of highscore is added

    var sharingItems = [AnyObject]()

    var shareButtonHighscore = NSUserDefaults.standardUserDefaults().objectForKey("highscore") as Int!

    sharingItems.append("Just hit \(shareButtonHighscore)! Beat it! #Swath")

    UIGraphicsBeginImageContextWithOptions(UIScreen.mainScreen().bounds.size, false, 0);
    self.view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
    var image:UIImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    sharingItems.append(image)

    let activityViewController = UIActivityViewController(activityItems: sharingItems, applicationActivities: nil)

    var barButtonItem: UIBarButtonItem! = UIBarButtonItem()

    activityViewController.excludedActivityTypes = [UIActivityTypeCopyToPasteboard,UIActivityTypeAirDrop,UIActivityTypeAddToReadingList,UIActivityTypeAssignToContact,UIActivityTypePostToTencentWeibo,UIActivityTypePostToVimeo,UIActivityTypePrint,UIActivityTypeSaveToCameraRoll,UIActivityTypePostToWeibo]

    self.presentViewController(activityViewController, animated: true, completion: nil)

}

As you can see, I'm programming in Swift, in the SpriteKit Framework, and I don't understand why the app is crashing.

I'm receiving this error:

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

What can I do to fix this problem?

tdh
  • 884
  • 1
  • 11
  • 22
  • > What can I do to fix this problem? -- 1. read the error message. 2. check docs on `UIPopoverController` – Mundi Feb 16 '15 at 19:50

5 Answers5

31

Before presenting the UIActivityViewController, add in this line of code:

activityViewController.popoverPresentationController?.sourceView = self.view

This way, the view controller knows in which frame of the GameViewController to appear in.

tdh
  • 884
  • 1
  • 11
  • 22
4

If you read the error it says how to fix it, you need to set the barButtonItem or sourceView from which to present the popover from, in your case:

func shareButtonPress(pressedButton: UIBarButtonItem) { 

    ...

    activityViewController.popoverPresentationController.barButtonItem = pressedButton

    self.presentViewController(activityViewController, animated: true, completion: nil)
}
Steve
  • 2,526
  • 2
  • 20
  • 30
  • Now I'm getting this error: `[MyGame.GameViewController shareButtonPress]: unrecognized selector sent to instance 0x15f8c610'` – tdh Feb 17 '15 at 19:02
  • What can I do to correct this? I can't replace UIBarButtonItem with the name of the actual button, because the actual button is defined in GameScene. – tdh Feb 17 '15 at 19:04
  • How do you add the target to the UIBarButtonItem? – Steve Feb 18 '15 at 12:37
  • This is a much better solution than others, because this view controller should be shown at top of "caller" view. – artem Jun 20 '20 at 19:02
2

Swift 5:

Check if the device is iPhone or iPad and based on that add a sourceView and present the activityController

let activity = UIActivityViewController(activityItems: [self], applicationActivities: nil)
if UIDevice.current.userInterfaceIdiom == .phone {
    UIApplication.topViewController?.present(activity, animated: true, completion: nil)
} else {
    activity.popoverPresentationController?.sourceView = UIApplication.topViewController!.view
    UIApplication.topViewController?.present(activity, animated: true, completion: nil)
}
Keshu R.
  • 5,045
  • 1
  • 18
  • 38
1

There are two option, the action came from a UIBarButtonitem or UIButton that is a UIView.

func shareButtonPress() {

    ...

    if let actv = activityViewController.popoverPresentationController {
        actv.barButtonItem = someBarButton // if it is a UIBarButtonItem

        // Or if it is a view you can get the view rect
        actv.sourceView = someView
        // actv.sourceRect = someView.frame // you can also specify the CGRect
    }

    self.presentViewController(activityViewController, animated: true, completion: nil)
}

You may have to add a sender to your function like func shareButtonPress(sender: UIBarButtonItem) or func shareButtonPress(sender: UIButton)

Heberti Almeida
  • 1,440
  • 18
  • 27
1

I added for Swift 3:

activityViewController.popoverPresentationController?.sourceView = self.view

fixed my issue.

Whirlwind
  • 14,286
  • 11
  • 68
  • 157
Anas
  • 335
  • 5
  • 7