UIActivityViewController在iOS8 iPad上崩溃

我目前正在使用XCode 6(Beta 6)testing我的应用程序。 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.'

我在iPhone 7和iOS 8上都使用以下代码

 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]; 

我也遇到了类似的崩溃在我的其他应用程序。 你能指导我吗? iOS8中的UIActivityViewController有什么改变? 我查了一下,但是没有发现任何东西

在iPad上,活动视图控制器将使用新的UIPopoverPresentationController作为popup窗口显示,它要求您使用以下三个属性之一指定popup窗口的定位点:

  • barButtonItem
  • sourceView
  • sourceRect

为了指定锚点,您将需要获取对UIActivityController的UIPopoverPresentationController的引用,并设置其中一个属性,如下所示:

 if ( [activityViewController respondsToSelector:@selector(popoverPresentationController)] ) { // iOS8 activityViewController.popoverPresentationController.sourceView = parentView; } 

同样的问题是来到我的项目,然后我发现的解决scheme,打开iPad的UIActivityViewController我们必须使用UIPopoverController

这里是在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]; } 

快3

 let imageURL: URL = URL(string: product.images[0].fullImageUrlString)! let objectsToShare: [AnyObject] = [imageURL as AnyObject] let activityViewController = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil) activityViewController.popoverPresentationController?.sourceView = self.view activityViewController.excludedActivityTypes = [ UIActivityType.airDrop] self.present(activityViewController, animated: true, completion: nil) 

我在Swift 2.0中最近遇到了这个确切的问题(原始问题), UIActivityViewController在iPhones上工作正常,但在模拟iPad时导致崩溃。

我只是想添加到这个答案的线程,至less在Swift 2.0中,你不需要一个if语句。 你可以使popoverPresentationController可选的。

简单地说,接受的答案似乎是说,你可以只有一个sourceView,只是一个sourceRect,或只是一个barButtonItem,但根据Apple的UIPopoverPresentationController的文档,您需要以下之一:

  • barButtonItem
  • sourceView sourceRect

我正在处理的特定示例如下,我正在创build一个接收UIView (用于sourceView和sourceRect)和String (UIActivityViewController的唯一activityItem)的函数。

 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) } 

这个代码适用于iPhone和iPad(甚至tvOS我认为) – 如果设备不支持popoverPresentationController ,则提及它的两行代码基本上被忽略。

有点不错,只需要添加两行代码,或者只使用一个barButtonItem就可以完成所有工作。

我看到很多人在使用Swift代码时对iPhone / iPad等进行硬编码。

这不是必须的,你必须使用语言function。 以下代码假设您将使用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) } 

注意如何没有If语句或任何其他疯狂的事情。 可选的解包将在iPhone上为零,所以行vc.popoverPresentationController? 在iPhone上不会做任何事情。

使用Xamarin.iOS的解决scheme。

在我的例子中,我正在做一个屏幕截图,生成一个图像,并允许用户共享图像。 iPad上的popup窗口放在屏幕的中间。

 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); 

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) 

在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 } 

修复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) } 

迅速:

  let activityViewController = UIActivityViewController(activityItems: sharingItems, applicationActivities: nil) //if iPhone if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Phone) { self.presentViewController(activityViewController, animated: true, completion: nil) } else { //if iPad // Change Rect to position Popover var popoverCntlr = UIPopoverController(contentViewController: activityViewController) 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) } 

Swift 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) } 

swift = ios7 / ios8

 let activityViewController = UIActivityViewController(activityItems: sharingItems, applicationActivities: nil) //if iPhone if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Phone) { // go on.. } else { //if iPad if activityViewController.respondsToSelector(Selector("popoverPresentationController")) { // on iOS8 activityViewController.popoverPresentationController!.barButtonItem = self.shareButtonItem; } } self.presentViewController(activityViewController, animated: true, completion: nil) 

我发现这个解决scheme首先,你的视图控制器呈现popup窗口应该实现<UIPopoverPresentationControllerDelegate>协议。

接下来,你需要设置popoverPresentationController的委托。

添加这些function:

 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Assuming you've hooked this all up in a Storyboard with a popover presentation style if ([segue.identifier isEqualToString:@"showPopover"]) { UINavigationController *destNav = segue.destinationViewController; PopoverContentsViewController *vc = destNav.viewControllers.firstObject; // This is the important part UIPopoverPresentationController *popPC = destNav.popoverPresentationController; popPC.delegate = self; } } - (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController: (UIPresentationController *)controller { return UIModalPresentationNone; } 

我尝试了下一个代码,它的工作原理:

首先在您的视图控制器中放置一个酒吧button项目,然后创build一个IBOutlet:

@property(weak,nonatomic)IBOutlet UIBarButtonItem *barButtonItem;

接下来在.m文件中: yourUIActivityViewController.popoverPresentationController.barButtonItem = self.barButtonItem;

对于Swift 2.0。 我发现,如果您试图将popup窗口锚定到iPad上的共享button,这会起作用。 这假定您已经为工具栏中的共享button创build了一个sockets。

 func share(sender: AnyObject) { let firstActivityItem = "test" let activityViewController = UIActivityViewController(activityItems: [firstActivityItem], applicationActivities: nil) if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Phone { self.presentViewController(activityViewController, animated: true, completion: nil) } else { if activityViewController.respondsToSelector("popoverPresentationController") { activityViewController.popoverPresentationController!.barButtonItem = sender as? UIBarButtonItem self.presentViewController(activityViewController, animated: true, completion: nil) } } } 

要小心,如果你正在开发的iPad使用迅速,它将在debugging工作正常,但将在发布时崩溃。 为了使它与testFlight和AppStore一起工作,禁用swift的优化使用-none for release。