UIActivityViewController在iOS 8 iPad上崩溃

Bhu*_*hta 279 objective-c ios uiactivityviewcontroller ios8

我目前正在使用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.
Run Code Online (Sandbox Code Playgroud)

我正在为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];
Run Code Online (Sandbox Code Playgroud)

我也得到了一个类似的崩溃我的其他应用程序.你能指导我吗?iOS 8中的UIActivityViewController有什么变化吗?我查了但是我没有找到任何关于此的内容

mmc*_*omb 458

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

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

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

  • @Daljeet这将在iOS7上崩溃,因为UIActivityController在那里没有属性popoverPresentationController.使用此代码使其在iOS8和iOS7上工作:`if([activityViewController respondsToSelector:@selector(popoverPresentationController)]){// iOS8 activityViewController.popoverPresentationController.sourceView = _shareItem; }` (48认同)
  • @bluebamboo为什么不将你的建议添加为答案的编辑.在这些评论中很容易错过您的重要信息. (10认同)
  • @Daljeet一种简单的方法是将1x1透明视图放在任何你想要弹出窗口点的地方,并将其用作锚视图. (4认同)
  • 在iOS8中,sourceRect对我不起作用.我不得不用那个rect创建一个souceView,并且运行正常. (4认同)
  • @Thanks mmccomb,我已经应用了你的代码,它在iOS 8上运行正常,但是我的应用程序在iOS 7上崩溃了.我在stackoverflow上发布了同样的问题,这里是链接:http://stackoverflow.com/questions/26034149/ uiactivityviewcontroller-issue-ios-7-and-ios-8#26034622帮助表示赞赏 (3认同)

Har*_*kar 186

同样的问题来到我的项目然后我找到解决方案,在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];
}
Run Code Online (Sandbox Code Playgroud)

对于swift 4.2

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)
}
Run Code Online (Sandbox Code Playgroud)

  • 对于"更新"的Swift语法,UIPopoverArrowDirectionAny应为UIPopoverArrowDirection.Any,UIUserInterfaceIdiomPhone为UIUserInterfaceIdiom.Phone (5认同)
  • 在iOS 9中不推荐使用UIPopOverController. (3认同)

Gal*_*len 38

我最近在Swift 2.0中遇到了这个问题(原始问题),这UIActivityViewController对于iPhone来说效果很好,但在模拟iPad时会导致崩溃.

我只想在这里添加这个答案的线程,至少在Swift 2.0中,你不需要if语句.你可以popoverPresentationController选择.

快速地说,接受的答案似乎是说你可能只有一个sourceView,只是一个sourceRect,或者只是一个barButtonItem,但根据Apple的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)
}
Run Code Online (Sandbox Code Playgroud)

这段代码适用于iPhone和iPad(我认为甚至是tvOS) - 如果设备不支持popoverPresentationController,提到它的两行代码基本上都被忽略了.

有点好,你需要做的就是让它适用于iPad只需要添加两行代码,或者如果你使用的是barButtonItem就可以添加一行代码!

  • 这个解决方案似乎比其他必须使用`respondsToSelector`或`UIUserInterfaceIdiom`的解决方案更清晰,它似乎更适合Swift作为一种语言.虽然`respondsToSelector`似乎对于iOS7来说是必要的,但如果使用较新版本的iOS,这肯定是要走的路. (2认同)

Mar*_*ini 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)
 }
Run Code Online (Sandbox Code Playgroud)

注意没有If语句或任何其他疯狂的东西.iPhone上的可选展开将为零,因此该行vc.popoverPresentationController?不会在iPhone上执行任何操作.


ben*_*ben 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);
Run Code Online (Sandbox Code Playgroud)


bat*_*rbb 9

SwiftUI 版本

func presentActivityView(items: [Any]){
    let activityController = UIActivityViewController(activityItems: items, applicationActivities: nil)
    if UIDevice.current.userInterfaceIdiom == .pad{
        activityController.popoverPresentationController?.sourceView = UIApplication.shared.windows.first
        activityController.popoverPresentationController?.sourceRect = CGRect(x:  UIScreen.main.bounds.width / 3, y:  UIScreen.main.bounds.height / 1.5, width: 400, height: 400)
    }
    UIApplication.shared.windows.first?.rootViewController?.present(activityController, animated: true, completion: nil)
}
Run Code Online (Sandbox Code Playgroud)


MPa*_*ulo 7

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)
Run Code Online (Sandbox Code Playgroud)

  • Swift 3不支持此功能 (3认同)

dro*_*dev 6

如果您UIActivityViewController在单击时显示,请UIBarButtonItem使用以下代码:

activityViewController.popoverPresentationController?.barButtonItem = sender
Run Code Online (Sandbox Code Playgroud)

否则,如果您使用另一个控件,例如 a UIButton,请使用以下代码:

activityViewController.popoverPresentationController?.sourceView = sender
activityViewController.popoverPresentationController?.sourceRect = sender.bounds
Run Code Online (Sandbox Code Playgroud)

从文档到UIPopoverPresentationController

var barButtonItem: UIBarButtonItem? { get set }
Run Code Online (Sandbox Code Playgroud)

为此属性分配一个值以将弹出框锚定到指定的栏按钮项。出现时,弹出框的箭头指向指定的项目。或者,您可以使用 sourceView 和 sourceRect 属性指定弹出框的锚点位置。


Nik*_*las 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
    }
Run Code Online (Sandbox Code Playgroud)


Dan*_*ean 5

斯威夫特 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)
}
Run Code Online (Sandbox Code Playgroud)


小智 5

Objective-C 的解决方案并使用 UIPopoverPresentationController

    UIActivityViewController *controller = /*Init your Controller*/;
    //if iPhone
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        [self presentViewController:controller animated:YES completion:nil];
    }
    //if iPad
    else {
        UIPopoverPresentationController* popOver = controller.popoverPresentationController
        if(popOver){
            popOver.sourceView = controller.view;
            popOver.sourceRect = CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/4, 0, 0);
            [self presentViewController:controller animated:YES completion:nil];
        }
    }
Run Code Online (Sandbox Code Playgroud)