UIActivityViewController 在 iOS 8 iPad 上崩溃
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25644054/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UIActivityViewController crashing on iOS 8 iPads
提问by Bhumit Mehta
I am currently testing my app with Xcode 6 (Beta 6). UIActivityViewController works fine with iPhone devices and simulators but crashes with iPad simulators and devices (iOS 8) with following logs
我目前正在使用 Xcode 6 (Beta 6) 测试我的应用程序。UIActivityViewController 在 iPhone 设备和模拟器上运行良好,但在 iPad 模拟器和设备 (iOS 8) 上崩溃,并显示以下日志
Terminating app due to uncaught exception 'NSGenericException',
reason: 'UIPopoverPresentationController
(<_UIAlertControllerActionSheetRegularPresentationController: 0x7fc7a874bd90>)
should have a non-nil sourceView or barButtonItem set before the presentation occurs.
I am using following code for iPhone and iPad for both iOS 7 as well as iOS 8
我正在为 iOS 7 和 iOS 8 的 iPhone 和 iPad 使用以下代码
NSData *myData = [NSData dataWithContentsOfFile:_filename];
NSArray *activityItems = [NSArray arrayWithObjects:myData, nil];
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:nil applicationActivities:nil];
activityViewController.excludedActivityTypes = @[UIActivityTypeCopyToPasteboard];
[self presentViewController:activityViewController animated:YES completion:nil];
I am getting a similar crash in of one my other app as well. Can you please guide me ? has anything changed with UIActivityViewController in iOS 8? I checked but i did not find anything on this
我的另一个应用程序也发生了类似的崩溃。你能指导我吗?iOS 8 中的 UIActivityViewController 有什么变化吗?我查过了,但我没有找到任何关于这个的东西
回答by mmccomb
On iPad the activity view controller will be displayed as a popover using the new UIPopoverPresentationController, it requires that you specify an anchor point for the presentation of the popover using one of the three following properties:
在 iPad 上,活动视图控制器将使用新的UIPopoverPresentationController显示为弹出框,它要求您使用以下三个属性之一为弹出框的呈现指定一个锚点:
In order to specify the anchor point you will need to obtain a reference to the UIActivityController's UIPopoverPresentationController and set one of the properties as follows:
为了指定锚点,您需要获取对 UIActivityController 的 UIPopoverPresentationController 的引用,并设置如下属性之一:
if ( [activityViewController respondsToSelector:@selector(popoverPresentationController)] ) {
// iOS8
activityViewController.popoverPresentationController.sourceView =
parentView;
}
回答by Hardik Thakkar
Same problem is come to my project then i found the solution that to open the UIActivityViewController
in iPad we have to use UIPopoverController
同样的问题出现在我的项目中,然后我找到了UIActivityViewController
在 iPad 中打开我们必须使用的解决方案UIPopoverController
Here is a code to use it in iPhone and iPad both:
这是在 iPhone 和 iPad 中使用它的代码:
//to attach the image and text with sharing
UIImage *image=[UIImage imageNamed:@"giraffe.png"];
NSString *str=@"Image form My app";
NSArray *postItems=@[str,image];
UIActivityViewController *controller = [[UIActivityViewController alloc] initWithActivityItems:postItems applicationActivities:nil];
//if iPhone
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
[self presentViewController:controller animated:YES completion:nil];
}
//if iPad
else {
// Change Rect to position Popover
UIPopoverController *popup = [[UIPopoverController alloc] initWithContentViewController:controller];
[popup presentPopoverFromRect:CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/4, 0, 0)inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
For swift 4.2 / swift 5
对于 swift 4.2 / swift 5
func openShareDilog() {
let text = "share text will goes here"
// set up activity view controller
let textToShare = [text]
let activityViewController = UIActivityViewController(activityItems: textToShare, applicationActivities: nil)
activityViewController.excludedActivityTypes = [.airDrop]
if let popoverController = activityViewController.popoverPresentationController {
popoverController.sourceRect = CGRect(x: UIScreen.main.bounds.width / 2, y: UIScreen.main.bounds.height / 2, width: 0, height: 0)
popoverController.sourceView = self.view
popoverController.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
}
self.present(activityViewController, animated: true, completion: nil)
}
回答by Galen
I was encountering this exact problem recently (the original question) in Swift 2.0, where UIActivityViewController
worked fine for iPhones, but caused crashes when simulating iPads.
我最近在 Swift 2.0 中遇到了这个确切的问题(原始问题),该问题UIActivityViewController
适用于 iPhone,但在模拟 iPad 时导致崩溃。
I just want to add to this thread of answers here that, at least in Swift 2.0, you don't need an if statement. You can just make the popoverPresentationController
optional.
我只想在这里添加这个答案线程,至少在 Swift 2.0 中,您不需要 if 语句。你可以只做popoverPresentationController
可选的。
As a quick aside, the accepted answer appears to be saying that you could have just a sourceView, just a sourceRect, or just a barButtonItem, but according to Apple's documentation for UIPopoverPresentationControlleryou need one of the following:
顺便说一句,接受的答案似乎是说您可以只有一个 sourceView、一个 sourceRect 或一个 barButtonItem,但根据Apple 的 UIPopoverPresentationController 文档,您需要以下其中一项:
- barButtonItem
- sourceView andsourceRect
- 条形按钮项
- sourceView和sourceRect
The particular example I was working on is below, where I am creating a function that takes in a UIView
(for the sourceView and sourceRect) and String
(the UIActivityViewController's sole activityItem).
我正在处理的特定示例如下,我正在创建一个函数,该函数接收UIView
(对于 sourceView 和 sourceRect)和String
(UIActivityViewController 的唯一活动项)。
func presentActivityViewController(sourceView: UIView, activityItem: String ) {
let activityViewController = UIActivityViewController(activityItems: [activityItem], applicationActivities: [])
activityViewController.popoverPresentationController?.sourceView = sourceView
activityViewController.popoverPresentationController?.sourceRect = sourceView.bounds
self.presentViewController(activityViewController, animated: true, completion: nil)
}
This code works on iPhone and iPad (and even tvOS I think) -- if the device does not support popoverPresentationController
, the two lines of code that mention it are essentially ignored.
这段代码适用于 iPhone 和 iPad(我认为甚至是 tvOS)——如果设备不支持popoverPresentationController
,那么提到它的两行代码基本上会被忽略。
Kinda nice that all you need to do to make it work for iPads is just add two lines of code, or just one if you're using a barButtonItem!
很好,您只需添加两行代码即可使其适用于 iPad,如果您使用的是 barButtonItem,则只需添加一行!
回答by Martin Marconcini
I see a lot of people hardcoding iPhone/iPad etc. while using Swift code.
我看到很多人在使用 Swift 代码时硬编码 iPhone/iPad 等。
This is not needed, you have to use the language features. The following code assumes you will use a UIBarButtonItem and will work on bothiPhone and iPad.
这不是必需的,您必须使用语言功能。下面的代码假定您要使用的UIBarButtonItem和将工作既iPhone和iPad。
@IBAction func share(sender: AnyObject) {
let vc = UIActivityViewController(activityItems: ["hello"], applicationActivities: nil)
vc.popoverPresentationController?.barButtonItem = sender as? UIBarButtonItem
self.presentViewController(vc, animated: true, completion: nil)
}
Notice how there are no If statements or any other crazy thing. The optional unwrapping will be nil on iPhone, so the line vc.popoverPresentationController?
will not do anything on iPhones.
注意这里没有 If 语句或任何其他疯狂的东西。iPhone 上的可选解包将为零,因此该行vc.popoverPresentationController?
不会在 iPhone 上执行任何操作。
回答by ben
Solution using Xamarin.iOS.
使用 Xamarin.iOS 的解决方案。
In my example I'm doing a screen capture, producing an image, and allowing the user to share the image. The pop up on the iPad is placed about in the middle of the screen.
在我的示例中,我正在执行屏幕截图、生成图像并允许用户共享图像。iPad 上的弹出窗口位于屏幕中间。
var activityItems = new NSObject[] { image };
var excludedActivityTypes = new NSString[] {
UIActivityType.PostToWeibo,
UIActivityType.CopyToPasteboard,
UIActivityType.AddToReadingList,
UIActivityType.AssignToContact,
UIActivityType.Print,
};
var activityViewController = new UIActivityViewController(activityItems, null);
//set subject line if email is used
var subject = new NSString("subject");
activityViewController.SetValueForKey(NSObject.FromObject("Goal Length"), subject);
activityViewController.ExcludedActivityTypes = excludedActivityTypes;
//configure for iPad, note if you do not your app will not pass app store review
if(null != activityViewController.PopoverPresentationController)
{
activityViewController.PopoverPresentationController.SourceView = this.View;
var frame = UIScreen.MainScreen.Bounds;
frame.Height /= 2;
activityViewController.PopoverPresentationController.SourceRect = frame;
}
this.PresentViewController(activityViewController, true, null);
回答by MPaulo
Swift, iOS 9/10 (after UIPopoverController deprecated)
Swift,iOS 9/10(在 UIPopoverController 弃用后)
let activityViewController = UIActivityViewController(activityItems: sharingItems, applicationActivities: nil)
if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
if activityViewController.respondsToSelector(Selector("popoverPresentationController")) {
activityViewController.popoverPresentationController?.sourceView = self.view
}
}
self.presentViewController(activityViewController, animated: true, completion: nil)
回答by Niklas
In Swift to fix this for iPad, best way is to do like this I found.
在 Swift 中为 iPad 解决这个问题,最好的方法是像我发现的那样做。
let things = ["Things to share"]
let avc = UIActivityViewController(activityItems:things, applicationActivities:nil)
avc.setValue("Subject title", forKey: "subject")
avc.completionWithItemsHandler = {
(s: String!, ok: Bool, items: [AnyObject]!, err:NSError!) -> Void in
}
self.presentViewController(avc, animated:true, completion:nil)
if let pop = avc.popoverPresentationController {
let v = sender as! UIView // sender would be the button view tapped, but could be any view
pop.sourceView = v
pop.sourceRect = v.bounds
}
回答by datayeah
Fix for Swift 2.0
修复Swift 2.0
if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Phone {
self.presentViewController(activityVC, animated: true, completion: nil)
}
else {
let popup: UIPopoverController = UIPopoverController(contentViewController: activityVC)
popup.presentPopoverFromRect(CGRectMake(self.view.frame.size.width / 2, self.view.frame.size.height / 4, 0, 0), inView: self.view, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
}
回答by Daniel McLean
Swift 3:
斯威夫特 3:
class func openShareActions(image: UIImage, vc: UIViewController) {
let activityVC = UIActivityViewController(activityItems: [image], applicationActivities: nil)
if UIDevice.current.userInterfaceIdiom == .pad {
if activityVC.responds(to: #selector(getter: UIViewController.popoverPresentationController)) {
activityVC.popoverPresentationController?.sourceView = vc.view
}
}
vc.present(activityVC, animated: true, completion: nil)
}
回答by DronPop
If you show UIActivityViewController
when you click on an UIBarButtonItem
use the following code:
如果您UIActivityViewController
在单击时显示,请UIBarButtonItem
使用以下代码:
activityViewController.popoverPresentationController?.barButtonItem = sender
Otherwise, if you use another control, for example a UIButton
, use the following code:
否则,如果您使用另一个控件,例如 a UIButton
,请使用以下代码:
activityViewController.popoverPresentationController?.sourceView = sender
activityViewController.popoverPresentationController?.sourceRect = sender.bounds
From the documentation to the UIPopoverPresentationController
:
从文档到UIPopoverPresentationController
:
var barButtonItem: UIBarButtonItem? { get set }
Assign a value to this property to anchor the popover to the specified bar button item. When presented, the popover's arrow points to the specified item. Alternatively, you may specify the anchor location for the popover using the sourceView and sourceRect properties.
为此属性分配一个值以将弹出框锚定到指定的栏按钮项。出现时,弹出框的箭头指向指定的项目。或者,您可以使用 sourceView 和 sourceRect 属性指定弹出框的锚点位置。