Fabian Boulegue Fabian Boulegue - 1 month ago 16
Swift Question

Swift UIAltertController -> ActionSheet iPad iOS8 Crashes

currently i m running into big trouble with my ActionSheet. On iPhone it works great, but on iPad it only crashes

I create a new project with only one button

import UIKit

extension ViewController : UIActionSheetDelegate {

func actionSheet(actionSheet: UIActionSheet, didDismissWithButtonIndex buttonIndex: Int) {

if actionSheet.tag == 0 {
if buttonIndex == 1 {
// doing something for "product page"
} else if (buttonIndex == 2) {
// doing something for "video"
}
}
}

}

class ViewController: UIViewController, UIActionSheetDelegate {
@IBAction func test(sender: AnyObject) {

let systemVersion: NSInteger = (UIDevice.currentDevice().systemVersion as NSString).integerValue
if systemVersion < 8 {
// iOS7:
let action:UIActionSheet = UIActionSheet(title: "Change Map Type", delegate: self, cancelButtonTitle: "Back", destructiveButtonTitle: nil, otherButtonTitles: "Product Page", "Video")
action.tag = 0
action.showInView(self.view)
} else {
// iOS8:
let alertController: UIAlertController = UIAlertController(title: "Change Map Type", message: nil, preferredStyle: UIAlertControllerStyle.ActionSheet)
let cancelAction: UIAlertAction = UIAlertAction(title: "Back", style: UIAlertActionStyle.Cancel, handler: nil)
let button1action: UIAlertAction = UIAlertAction(title: "Product Page", style: UIAlertActionStyle.Default, handler: { (action: UIAlertAction!) -> () in
// doing something for "product page"
})
let button2action: UIAlertAction = UIAlertAction(title: "Video", style: UIAlertActionStyle.Default, handler: { (action: UIAlertAction!) -> () in
// doing something for "video"
})
alertController.addAction(cancelAction)
alertController.addAction(button1action)
alertController.addAction(button2action)

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

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}


}


As i sad on the iphone it works, but if i click the button on iPad the App crashes with


2014-09-25 14:54:52.784 test[9541:1970048] * Terminating app due to
uncaught exception 'NSGenericException', reason: 'Your application has
presented a UIAlertController () of
style UIAlertControllerStyleActionSheet. The modalPresentationStyle of
a UIAlertController with this style is UIModalPresentationPopover. You
must provide location information for this popover through the alert
controller's popoverPresentationController. You must provide either a
sourceView and sourceRect or a barButtonItem. If this information is
not known when you present the alert controller, you may provide it in
the UIPopoverPresentationControllerDelegate method
-prepareForPopoverPresentation.'
*
First throw call stack: ( 0 CoreFoundation 0x00613df6 exceptionPreprocess + 182 1 libobjc.A.dylib

0x01fdaa97 objc_exception_throw + 44 2 UIKit

0x0164da37 -[UIPopoverPresentationController
presentationTransitionWillBegin] + 3086 3 UIKit

0x00f54f75 __71-[UIPresentationController
_initViewHierarchyForPresentationSuperview:]_block_invoke + 1666 4 UIKit 0x00f53554
__56-[UIPresentationController runTransitionForCurrentState]_block_invoke + 226 5 UIKit

0x00f8721b __40+[UIViewController _scheduleTransition:]_block_invoke +
18 6 UIKit 0x00e4d62e
___afterCACommitHandler_block_invoke + 15 7 UIKit 0x00e4d5d9 _applyBlockToCFArrayCopiedToStack + 415 8 UIKit

0x00e4d3ee _afterCACommitHandler + 545 9 CoreFoundation

0x00536fbe
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION
+ 30 10 CoreFoundation 0x00536f00 __CFRunLoopDoObservers
+ 400 11 CoreFoundation 0x0052c93a __CFRunLoopRun + 1226 12 CoreFoundation 0x0052c1ab CFRunLoopRunSpecific + 443 13 CoreFoundation

0x0052bfdb CFRunLoopRunInMode + 123 14 GraphicsServices

0x0438424f GSEventRunModal + 192 15 GraphicsServices

0x0438408c GSEventRun + 104 16 UIKit

0x00e23e16 UIApplicationMain + 1526 17 test

0x00085e9e top_level_code + 78 18 test

0x00085edb main + 43 19 libdyld.dylib

0x0273eac9 start + 1 20 ???

0x00000001 0x0 + 1 ) libc++abi.dylib: terminating with uncaught
exception of type NSException


Project can be found at https://www.dropbox.com/s/54jqd8nsc67ll5g/test.zip?dl=0 for download and try.

Answer

The error message is telling you that you need to give the alert controller's popoverPresentationController a location so that it can position itself properly. This is easy to do -- just check to see if there's a popover controller and add the sender as the source.

If your button is a UIBarButtonItem:

if let popoverController = alertController.popoverPresentationController {
    popoverController.barButtonItem = sender
}
self.presentViewController(alertController, animated: true, completion: nil)

Otherwise:

if let popoverController = alertController.popoverPresentationController {
    popoverController.sourceView = sender
    popoverController.sourceRect = sender.bounds
}
self.presentViewController(alertController, animated: true, completion: nil)
Comments