2014-09-03 133 views
252

我目前正在使用XCode 6(Beta 6)测试我的应用程序。 UIActivityViewController正常工作与iPhone设备和模拟器,但与iPad模拟器和设备(iOS版8)以下日志UIActivityViewController在iOS8 iPad上崩溃

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和iPad的代码量。iOS 7和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]; 

我也遇到了类似的崩溃在我的其他应用程序以及。你能指导我吗? iOS 8中的UIActivityViewController有什么变化?我检查了但我在此找不到任何东西

+0

我甚至没有得到崩溃这么多的信息,从拉我的头发这一个 – 2015-05-20 20:36:27

+0

下面的答案为成语测试。你应该使用@Galen的答案。 – doozMen 2016-04-18 10:37:26

回答

422

在iPad上,活动视图控制器将使用新的UIPopoverPresentationController显示为弹出窗口,它要求您使用三个窗口中的一个为展现弹出窗口指定一个锚点以下性质:

为了指定的锚点,您将需要获得对UIActivityController的UIPopoverPresentationController参考并设置属性之一,如下所示:

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

@thanks mmccomb其工作正常,请问我可以如何更改UIActivityViewController的位置。 – Daljeet 2014-09-23 11:33:11

+4

@Daljeet一个简单的方法是放置一个1x1透明视图,无论你希望弹出点的位置出现,并用它作为锚点视图。 – 2014-09-24 05:01:20

+3

@感谢mmccomb,我已经在iOS 8上应用了你的代码,它在iOS 8上工作正常,但是我的应用在iOS 7上崩溃了。我在这里发布了一个和stackoverflow相同的问题链接:http://stackoverflow.com/questions/26034149/uiactivityviewcontroller-issue-ios-7-and-ios-8#26034622帮助表示赞赏 – Daljeet 2014-09-25 10:23:07

0

我发现这个解决方案 首先,这是呈现酥料饼您的视图控制器应实施<UIPopoverPresentationControllerDelegate>协议。

接下来,您需要设置popoverPresentationController的代表。

添加这些功能:

- (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; 
} 
164

同样的问题来我的项目,然后我找到了解决方案,在打开UIActivityViewController iPad的我们必须使用UIPopoverController

这里是在iPhone和iPad上使用它的代码

//to attach the image and text with sharing 
UIImage *image=[UIImage imageNamed:@"giraffe.png"]; 
NSString *[email protected]"Image form My app"; 
NSArray *[email protected][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) 
+5

对于“更新”的Swift语法,UIPopoverArrowDirectionAny应该是UIPopoverArrowDirection.Any,而UIUserInterfaceIdiomPhone是UIUserInterfaceIdiom.Phone – 2015-09-22 18:38:52

+1

非常感谢,结合EPage_Ed的注释,它适用于XCode 7和SWIFT 2。 – 2015-10-09 04:14:04

+1

iOS 9不推荐使用UIPopoverController。 – cbartel 2015-10-20 18:59:40

10

使用溶液Xamarin.iOS。

在我的示例中,我正在执行屏幕截图,生成图像并允许用户共享图像。 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); 
+0

使用@Galen答案。应该也适用于Xamarin – doozMen 2016-04-18 10:34:25

+0

非常感谢你:)与Xamarin Forms一起使用依赖服务 – 2016-06-15 15:43:23

0

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

先放一栏按钮项在您的视图控制器 然后创建一个IBOutlet:

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

下一个在.M文件:yourUIActivityViewController.popoverPresentationController.barButtonItem = self.barButtonItem;

3

Swift:

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) 

    } 
1

迅速= 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) 
-5

要小心,如果你正在为iPad使用迅速发展,它将工作在调试正常,但将在发行崩溃。为了使其与testFlight和AppStore一起工作,请使用-none进行发布,禁用swift的优化。

5

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

使用@Galen答案。定位iOS8时无成语检查+ – doozMen 2016-04-18 10:35:04

4

修正了雨燕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) 
    } 
+2

UIPopoverController已被弃用。 – LevinsonTechnologies 2016-02-27 23:55:07

+1

谢谢!它帮助我很多。 – Oscar 2016-06-08 18:56:49

34

我是在雨燕2.0,其中UIActivityViewController工作正常的iPhone,但是模拟的iPad时造成死机最近遇到此确切的问题(原题)。

我只想在这里添加到这个答案的主题,至少在Swift 2.0中,你不需要if语句。您可以使popoverPresentationController为可选项。

作为一个快速之外,公认的答案似乎是说,你可能只是一个sourceView,只是一个sourceRect,或只是一个barButtonItem,但根据Apple's documentation for UIPopoverPresentationController你需要以下之一:

  • barButtonItem
  • sourceView sourceRect

我工作的具体例子如下,在那里我创建一个函数,它在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,您只需要添加两行代码即可!

+2

这个解决方案似乎比其他解决方案更加简洁,它不得不使用'respondsToSelector'或'UIUserInterfaceIdiom',它似乎更适合Swift作为一种语言。虽然'respondsToSelector'好像是iOS7所必需的,如果使用更新版本的iOS,这绝对是一条好路径。 – Marcus 2016-01-04 20:51:59

+0

非常好只有你需要针对iOS8 + – doozMen 2016-04-18 10:33:55

-1

对于Swift 2.0。我发现,如果您试图将弹出窗口锚定到iPad上的分享按钮,这会起作用。这假定您已经为工具栏中的分享按钮创建了一个插口。

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

    } 
} 
16

我看到很多人在使用Swift代码时硬编码iPhone/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) 
} 

注意如何没有If语句或任何其他疯狂的事情。 iPhone上的可选展开功能将无效,因此vc.popoverPresentationController?行不会在iPhone上执行任何操作。

+0

这将看起来在本教程的上下文中:https://www.hackingwithswift.com/read/3/2/uiactivityviewcontroller-explained – 2016-02-29 10:01:20

+1

本教程没有提到popoverPresentationController ,这样代码将在iPad iOS 9.x上崩溃。解决方案是在呈现视图控制器之前添加'vc.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItem'。 – 2016-02-29 17:14:52

+0

嗨马丁...我已经有一条线看起来像这样,在'shareTapped()':'vc.popoverPresentationController?.barButtonItem = sender as? UIBarButtonItem'仍然崩溃。我究竟做错了什么?当我在这里时,我如何使用Facebook,Twitter等不同的共享服务填充popover? – 2016-03-01 01:19:43

6

斯威夫特,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) 
+2

Swift 3不支持这个 – 2016-10-20 19:00:39

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