UIAlertController 崩溃 (iPad)
UIAlertController is Crashed (iPad)
我正在使用 Xcode 6 开发一个 iOS 应用程序。
当我使用UIAlertController
时,它在iPhone 6 模拟器上运行良好,但在iPad 模拟器上崩溃。
我的问题是点击 "share",然后它可能会崩溃。
我该如何解决?
这是我的代码:
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject] {
var shareAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Share", handler: { (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in
let shareMenu = UIAlertController(title: nil, message: "Share using", preferredStyle: .ActionSheet)
let twitterAction = UIAlertAction(title: "Twitter", style: UIAlertActionStyle.Default, handler: nil)
let facebookAction = UIAlertAction(title: "Facebook", style: UIAlertActionStyle.Default, handler: nil)
let emailAction = UIAlertAction(title: "Email", style: UIAlertActionStyle.Default, handler: nil)
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)
shareMenu.addAction(twitterAction)
shareMenu.addAction(facebookAction)
shareMenu.addAction(emailAction)
shareMenu.addAction(cancelAction)
self.presentViewController(shareMenu, animated: true, completion: nil)
}
)
Xcode 显示了这条消息:
******Terminating app due to uncaught exception 'NSGenericException', reason: 'Your application has presented a UIAlertController (<UIAlertController: 0xaf71c80>) 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[![enter image description here][1]][1] present the alert controller, you may provide it in the UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation.'
*** First throw call stack:
(
0 CoreFoundation 0x0023c746 __exceptionPreprocess + 182
1 libobjc.A.dylib 0x01c7aa97 objc_exception_throw + 44
2 UIKit 0x012c4062 -[UIPopoverPresentationController presentationTransitionWillBegin] + 3086
3 UIKit 0x00bda174 __71-[UIPresentationController _initViewHierarchyForPresentationSuperview:]_block_invoke + 1549
4 UIKit 0x00bd8247 __56-[UIPresentationController runTransitionForCurrentState]_block_invoke + 198
5 UIKit 0x00c0d31b __40+[UIViewController _scheduleTransition:]_block_invoke + 18
6 UIKit 0x00ac6862 ___afterCACommitHandler_block_invoke + 15
7 UIKit 0x00ac680d _applyBlockToCFArrayCopiedToStack + 415
8 UIKit 0x00ac6622 _afterCACommitHandler + 549
9 CoreFoundation 0x0015d86e __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
10 CoreFoundation 0x0015d7b0 __CFRunLoopDoObservers + 400
11 CoreFoundation 0x001531ea __CFRunLoopRun + 1226
12 CoreFoundation 0x00152a5b CFRunLoopRunSpecific + 443
13 CoreFoundation 0x0015288b CFRunLoopRunInMode + 123
14 GraphicsServices 0x047b82c9 GSEventRunModal + 192
15 GraphicsServices 0x047b8106 GSEventRun + 104
16 UIKit 0x00a9c106 UIApplicationMain + 1526
17 Mars I 0x0001c724 main + 180
18 libdyld.dylib 0x02392ac9 start + 1
19 ??? 0x00000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException******
试试这个代码:
shareMenu.popoverPresentationController.sourceView = self.view
shareMenu.popoverPresentationController.sourceRect = CGRectMake(self.view.bounds.size.width / 2.0, self.view.bounds.size.height / 2.0, 1.0, 1.0)
self.presentViewController(shareMenu, animated: true, completion: nil)
要使其独立于设备,请按照下面的代码片段所示使用它。对于 iPhone / 紧凑型设备上的 popoverPresentationController,此代码 return nil,因此您可以在通用项目中安全地使用它。
if let popoverPresentationController = shareMenu.popoverPresentationController {
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = sender.bounds
}
self.presentViewController(shareMenu, animated: true, completion: nil)
我也遇到了同样的问题,终于找到解决办法了。
这是我针对 Objective-C 的解决方案:
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Select you option:"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *action = [UIAlertAction actionWithTitle:@“share”
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
// do other things
}];
[alertController addAction:action];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action) {
}];
[alertController addAction:cancelAction];
// Remove arrow from action sheet.
[alertController.popoverPresentationController setPermittedArrowDirections:0];
//For set action sheet to middle of view.
CGRect rect = self.view.frame;
rect.origin.x = self.view.frame.size.width / 20;
rect.origin.y = self.view.frame.size.height / 20;
alertController.popoverPresentationController.sourceView = self.view;
alertController.popoverPresentationController.sourceRect = rect;
[self presentViewController:alertController animated:YES completion:nil];
我使用这个方便的扩展来创建永不崩溃的操作表
extension UIAlertController {
class func actionSheetWith(title: String?, message: String?, sourceView: UIView?, sourceFrame: CGRect?) -> UIAlertController {
let actionController = UIAlertController(title: title, message: message, preferredStyle: .actionSheet)
if actionController.responds(to: #selector(getter: popoverPresentationController)) {
actionController.popoverPresentationController?.sourceView = sourceView ?? StoryboardHelper.tabBarControllerTopController()?.view
actionController.popoverPresentationController?.sourceRect = sourceFrame ?? CGRect(x: 0, y: 0, width: 0, height: 0)
}
return actionController
}
}
Swift 3
shareMenu.popoverPresentationController?.sourceView = self.view
shareMenu.popoverPresentationController?.sourceRect =
CGRect(x: view.bounds.size.width,
y: view.bounds.size.height-80,
width: 1.0, height: 1.0)
source rect 是您要显示弹出视图的起点。
Swift 4
popoverPresentationController.permittedArrowDirections = .init(rawValue: 0)
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
我使用这段代码,非常简单易懂,也许我可以帮助任何
//if iPhone
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
[self presentViewController:actionSheet animated:YES completion:nil];
}
//if iPad
else {
// Change Rect to position Popover
UIPopoverController *popup = [[UIPopoverController alloc] initWithContentViewController:actionSheet];
[popup presentPopoverFromRect:CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/4, 0, 0)inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
reference: ActionSheet Popover on iPad in Swift
创建弹出控制器:
let alertController = UIAlertController(title: nil, message: "Alert message.", preferredStyle: .actionSheet)
self.present(alertController, animated: true, completion: nil)
如果你想用指标视图显示警报应该:
if let popoverController = alertController.popoverPresentationController {
popoverController.barButtonItem = sender
}
with indicator
在中心显示警报:
if let popoverController = alertController.popoverPresentationController {
popoverController.sourceView = self.view
popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
}
center with indicator
中心无指标:
if let popoverController = alertController.popoverPresentationController {
popoverController.sourceView = self.view
popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
popoverController.permittedArrowDirections = []
}
center no indicator
对于iOS 13
用过。
if #available(iOS 13.0, *) {
if let popoverPresentationController = actionSheet.popoverPresentationController {
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = sender.frame
}
self.present(actionSheet, animated: true, completion: nil)
} else {
actionSheet.popoverPresentationController?.sourceView = self.view
actionSheet.popoverPresentationController?.sourceRect = sender.frame
actionSheet.show()
}
如果您不需要将警报显示为弹出窗口,您可以在初始化 AlertViewController
时简单地使用 UIAlertController.Style.alert
作为首选样式。
let shareMenu = UIAlertController(title: nil, message: "Share using", preferredStyle: .alert)
我发现这个link有用,对我有用
https://medium.com/@nickmeehan/actionsheet-popover-on-ipad-in-swift-5768dfa82094
为调整对齐方式进行了如下细微改动。
if let popoverPresentationController = alert.popoverPresentationController {
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.size.height * 0.85, width: 0, height: 0)
popoverPresentationController.permittedArrowDirections = []
}
我正在使用 Xcode 6 开发一个 iOS 应用程序。
当我使用UIAlertController
时,它在iPhone 6 模拟器上运行良好,但在iPad 模拟器上崩溃。
我的问题是点击 "share",然后它可能会崩溃。 我该如何解决?
这是我的代码:
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject] {
var shareAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Share", handler: { (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in
let shareMenu = UIAlertController(title: nil, message: "Share using", preferredStyle: .ActionSheet)
let twitterAction = UIAlertAction(title: "Twitter", style: UIAlertActionStyle.Default, handler: nil)
let facebookAction = UIAlertAction(title: "Facebook", style: UIAlertActionStyle.Default, handler: nil)
let emailAction = UIAlertAction(title: "Email", style: UIAlertActionStyle.Default, handler: nil)
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)
shareMenu.addAction(twitterAction)
shareMenu.addAction(facebookAction)
shareMenu.addAction(emailAction)
shareMenu.addAction(cancelAction)
self.presentViewController(shareMenu, animated: true, completion: nil)
}
)
Xcode 显示了这条消息:
******Terminating app due to uncaught exception 'NSGenericException', reason: 'Your application has presented a UIAlertController (<UIAlertController: 0xaf71c80>) 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[![enter image description here][1]][1] present the alert controller, you may provide it in the UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation.'
*** First throw call stack:
(
0 CoreFoundation 0x0023c746 __exceptionPreprocess + 182
1 libobjc.A.dylib 0x01c7aa97 objc_exception_throw + 44
2 UIKit 0x012c4062 -[UIPopoverPresentationController presentationTransitionWillBegin] + 3086
3 UIKit 0x00bda174 __71-[UIPresentationController _initViewHierarchyForPresentationSuperview:]_block_invoke + 1549
4 UIKit 0x00bd8247 __56-[UIPresentationController runTransitionForCurrentState]_block_invoke + 198
5 UIKit 0x00c0d31b __40+[UIViewController _scheduleTransition:]_block_invoke + 18
6 UIKit 0x00ac6862 ___afterCACommitHandler_block_invoke + 15
7 UIKit 0x00ac680d _applyBlockToCFArrayCopiedToStack + 415
8 UIKit 0x00ac6622 _afterCACommitHandler + 549
9 CoreFoundation 0x0015d86e __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
10 CoreFoundation 0x0015d7b0 __CFRunLoopDoObservers + 400
11 CoreFoundation 0x001531ea __CFRunLoopRun + 1226
12 CoreFoundation 0x00152a5b CFRunLoopRunSpecific + 443
13 CoreFoundation 0x0015288b CFRunLoopRunInMode + 123
14 GraphicsServices 0x047b82c9 GSEventRunModal + 192
15 GraphicsServices 0x047b8106 GSEventRun + 104
16 UIKit 0x00a9c106 UIApplicationMain + 1526
17 Mars I 0x0001c724 main + 180
18 libdyld.dylib 0x02392ac9 start + 1
19 ??? 0x00000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException******
试试这个代码:
shareMenu.popoverPresentationController.sourceView = self.view
shareMenu.popoverPresentationController.sourceRect = CGRectMake(self.view.bounds.size.width / 2.0, self.view.bounds.size.height / 2.0, 1.0, 1.0)
self.presentViewController(shareMenu, animated: true, completion: nil)
要使其独立于设备,请按照下面的代码片段所示使用它。对于 iPhone / 紧凑型设备上的 popoverPresentationController,此代码 return nil,因此您可以在通用项目中安全地使用它。
if let popoverPresentationController = shareMenu.popoverPresentationController {
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = sender.bounds
}
self.presentViewController(shareMenu, animated: true, completion: nil)
我也遇到了同样的问题,终于找到解决办法了。 这是我针对 Objective-C 的解决方案:
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Select you option:"
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *action = [UIAlertAction actionWithTitle:@“share”
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
// do other things
}];
[alertController addAction:action];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action) {
}];
[alertController addAction:cancelAction];
// Remove arrow from action sheet.
[alertController.popoverPresentationController setPermittedArrowDirections:0];
//For set action sheet to middle of view.
CGRect rect = self.view.frame;
rect.origin.x = self.view.frame.size.width / 20;
rect.origin.y = self.view.frame.size.height / 20;
alertController.popoverPresentationController.sourceView = self.view;
alertController.popoverPresentationController.sourceRect = rect;
[self presentViewController:alertController animated:YES completion:nil];
我使用这个方便的扩展来创建永不崩溃的操作表
extension UIAlertController {
class func actionSheetWith(title: String?, message: String?, sourceView: UIView?, sourceFrame: CGRect?) -> UIAlertController {
let actionController = UIAlertController(title: title, message: message, preferredStyle: .actionSheet)
if actionController.responds(to: #selector(getter: popoverPresentationController)) {
actionController.popoverPresentationController?.sourceView = sourceView ?? StoryboardHelper.tabBarControllerTopController()?.view
actionController.popoverPresentationController?.sourceRect = sourceFrame ?? CGRect(x: 0, y: 0, width: 0, height: 0)
}
return actionController
}
}
Swift 3
shareMenu.popoverPresentationController?.sourceView = self.view
shareMenu.popoverPresentationController?.sourceRect =
CGRect(x: view.bounds.size.width,
y: view.bounds.size.height-80,
width: 1.0, height: 1.0)
source rect 是您要显示弹出视图的起点。
Swift 4
popoverPresentationController.permittedArrowDirections = .init(rawValue: 0)
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
我使用这段代码,非常简单易懂,也许我可以帮助任何
//if iPhone
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
[self presentViewController:actionSheet animated:YES completion:nil];
}
//if iPad
else {
// Change Rect to position Popover
UIPopoverController *popup = [[UIPopoverController alloc] initWithContentViewController:actionSheet];
[popup presentPopoverFromRect:CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/4, 0, 0)inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
reference: ActionSheet Popover on iPad in Swift
创建弹出控制器:
let alertController = UIAlertController(title: nil, message: "Alert message.", preferredStyle: .actionSheet)
self.present(alertController, animated: true, completion: nil)
如果你想用指标视图显示警报应该:
if let popoverController = alertController.popoverPresentationController {
popoverController.barButtonItem = sender
}
with indicator
在中心显示警报:
if let popoverController = alertController.popoverPresentationController {
popoverController.sourceView = self.view
popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
}
center with indicator
中心无指标:
if let popoverController = alertController.popoverPresentationController {
popoverController.sourceView = self.view
popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
popoverController.permittedArrowDirections = []
}
center no indicator
对于iOS 13
用过。
if #available(iOS 13.0, *) {
if let popoverPresentationController = actionSheet.popoverPresentationController {
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = sender.frame
}
self.present(actionSheet, animated: true, completion: nil)
} else {
actionSheet.popoverPresentationController?.sourceView = self.view
actionSheet.popoverPresentationController?.sourceRect = sender.frame
actionSheet.show()
}
如果您不需要将警报显示为弹出窗口,您可以在初始化 AlertViewController
时简单地使用 UIAlertController.Style.alert
作为首选样式。
let shareMenu = UIAlertController(title: nil, message: "Share using", preferredStyle: .alert)
我发现这个link有用,对我有用
https://medium.com/@nickmeehan/actionsheet-popover-on-ipad-in-swift-5768dfa82094
为调整对齐方式进行了如下细微改动。
if let popoverPresentationController = alert.popoverPresentationController {
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.size.height * 0.85, width: 0, height: 0)
popoverPresentationController.permittedArrowDirections = []
}