Skip to content

UIActivityViewControllers and iPads

TIL: Sometimes developing for iPads is a huge pain in the ass.

table-flip
Disclaimer: No tables were harmed in the making of this app.

For some backstory: I’m in the process of building the MemeMe app for Udacity’s iOS Developer Nanodegree. This app allows users to take a photo, overlay some text to make it a meme, and send it to their friends. I’m building the app for iPad, because that’s the only iOS device I have and I want to test it on an actual piece of hardware.

But as I’m building the app, I simulate on a iPhone, because it’s faster and the screen is smaller.

So imagine my surprise when the app suddenly crashes on my iPad Mini when I go to share a meme I created. Returning to my computer to find the source of the error, I see the following:

Terminating app due to uncaught exception 'NSGenericException', reason: 'UIPopoverPresentationController...should have a non-nil sourceView or barButtonItem set before the presentation occurs.'

Um. Wut?

As any good programmer does, I took to StackOverflow to find a solution. And within five minutes I found myself a chunk of code that accomplished my goal (shout out to Hardik Thakkar).

But because I’m not satisfied to just copy code (I really need to know how it works), I dug a little deeper into the issue.

From what I gather, UIActivityViewControllers are presented modally on iPhones & iPods but are presented in a popover on iPads. So while modal presentation always comes up from the bottom, popovers need a defined anchor point. These can be defined in two ways:

  • barButtonItem: Anchors the popover to an item in a navigation bar or toolbar.
  • sourceView & sourceRect: Their combined power allows you to anchor the popover to specified location on the screen.

So in analyzing the code taken from StackOverflow, I currently check if the device is an iPhone or iPod, and if so, present the activity view controller as normal. If the device is not an iPhone or iPad, we present the view using a UIPopoverController. And we set the UIActivityView rectangle to be half of the current view’s width and a quarter of it’s height.

 // Launch Activity View for iPhone
 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Phone) {
   self.presentViewController(avc, animated: true, completion: nil)
 } else { // Launch Activity View for iPad
 // Change Rect to position Popover
   var popoverCntlr = UIPopoverController(contentViewController: avc)

   popoverCntlr.presentPopoverFromRect(CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/4, 0, 0),  inView: self.view, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
 }

And huzzah! A working ActivityView on the iPad. :)

Published inios

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *