UIActivityViewController在iPad上与sourceView或barButtonItem一起使用时崩溃

12

我遇到了一个看起来大多数人在iPad上使用UIActivityViewController时面临的情况;它会崩溃并显示以下错误:

Terminating app due to uncaught exception 'NSGenericException', reason: 'UIPopoverPresentationController (<_UIAlertControllerActionSheetRegularPresentationController: 0x7fc4f2d87d00>) should have a non-nil sourceView or barButtonItem set before the presentation occurs.

这是我的代码:

- (void)shareLeaflet
{
    NSString *forwardedString = [[NSString alloc] initWithFormat:@"Check out this leaflet\n\n %@ \n\nself.theURLToShare];
    UIActivityViewController *activityViewController = nil;

    if (IDIOM == IPAD)
    {
        NSLog(@"iPad");
        activityViewController.popoverPresentationController.sourceView = self.view;
//        activityViewController.popoverPresentationController.sourceRect = self.frame;
        [self presentViewController:activityViewController
                           animated:YES
                         completion:nil];

    }
    else
    {
        NSLog(@"iPhone");
        activityViewController = [[UIActivityViewController alloc] initWithActivityItems:[NSArray arrayWithObjects:forwardedString, nil] applicationActivities:nil];
        [self presentViewController:activityViewController animated:YES completion:nil];


    }

在我的viewDidLoad中,我有:

UIBarButtonItem *composeButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self                                    action:@selector(shareLeaflet)];

    self.navigationItem.rightBarButtonItem = composeButton;
}

这个视图是一个 UIPageViewController,展示了一些图片。当用户点击分享按钮时,我希望弹出 iOS 8 风格的共享面板。在 iPhone 上确实是这样的,但在 iPad 上它却不断崩溃。我在 Stack Overflow 上查找解决方法,但其中没有一个问题 (crash on showing UIPopOverPresentationController, iOS Crash: Terminating app due to uncaught exception reason: UIPopoverPresentationController should have a non-nil sourceView, UIWebViewTerminating app due to UIPopoverPresentationController, ios8 iPad uiwebview crashes while displaying popover when user taps drop down list HTML select tag等) 对我的情况适用。

我已经尝试了里面的所有解决方案,但还是不太理解需要什么操作。

这就是我想要实现的:

enter image description here 如果有任何想法,我会非常感激。

5个回答

19

在iPad上,您没有初始化activityViewController,因此它将始终为nil。

尝试:

- (void)shareLeaflet
{
    NSString *forwardedString = [[NSString alloc] initWithFormat:@"Check out this leaflet\n\n %@ \n\nself.theURLToShare];
    UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:[NSArray arrayWithObjects:forwardedString, nil] applicationActivities:nil];

    if (IDIOM == IPAD)
    {
        NSLog(@"iPad");
        activityViewController.popoverPresentationController.sourceView = self.view;
//        activityViewController.popoverPresentationController.sourceRect = self.frame;
        [self presentViewController:activityViewController
                           animated:YES
                         completion:nil];
    }
    else
    {
        NSLog(@"iPhone");
        [self presentViewController:activityViewController 
                          animated:YES 
                        completion:nil];
    }

然后像图像中那样显示它:(_shareBarButton是您希望弹出窗口从中显示的UIBarButtonItem)

- (void)shareLeaflet
    {
        NSString *forwardedString = [[NSString alloc] initWithFormat:@"Check out this leaflet\n\n %@ \n\nself.theURLToShare];
        UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:[NSArray arrayWithObjects:forwardedString, nil] applicationActivities:nil];

        if (IDIOM == IPAD)
        {
            NSLog(@"iPad");
            activityViewController.popoverPresentationController.sourceView = self.view;
    //        activityViewController.popoverPresentationController.sourceRect = self.frame;

           _popover = [[UIPopoverController alloc] initWithContentViewController:activityViewController];
           _popover.delegate = self;
           [_popover presentPopoverFromBarButtonItem:_shareBarButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
        }
        else
        {
            NSLog(@"iPhone");
            [self presentViewController:activityViewController 
                              animated:YES 
                            completion:nil];
        }

嗨@JDx - 哦,太简单了!对于那个简单的问题,很抱歉,但它像魔法一样奏效!谢谢!但是我想问一个后续问题 - 我可以控制弹出窗口来自哪一侧吗?现在,它是从屏幕左上角弹出的,但实际上按钮位于右上方。 - amitsbajaj
没问题!我认为你不能这样做,也许你可以使用一个 UiPopoverController 代替? - Jordan Davies
谢谢JD - 我只是想激活UIActivityViewController,就像iOS 8/9共享表单一样。我刚刚更新了问题,包括来自iPad Safari的图像 - 它直接出现在该按钮下面,但我的出现在左边,这很奇怪。 - amitsbajaj
哦,我认为你必须在UIPopoverController中显示activityViewController。我已经更新了我的答案,并附上了一些代码。 - Jordan Davies
1
太棒了,这个方法非常有效!非常感谢您在JDx上的帮助 - 真的非常感激! :) - amitsbajaj

3

iPad和iPhone iOS 14.4的最佳解决方案

let urlstring = "https://apps.apple.com/ae/app/"
let text = "some text for your app"
let url = NSURL(string: urlstring)
let textToShare = [url!,text] as [Any]
let activityViewController = UIActivityViewController(activityItems: textToShare as [Any], applicationActivities: nil)
    
activityViewController.excludedActivityTypes = [ UIActivity.ActivityType.airDrop, UIActivity.ActivityType.postToFacebook ,UIActivity.ActivityType.postToFlickr,UIActivity.ActivityType.postToTwitter,UIActivity.ActivityType.postToVimeo,UIActivity.ActivityType.mail,UIActivity.ActivityType.addToReadingList]

activityViewController.popoverPresentationController?.sourceView = self.view
activityViewController.popoverPresentationController?.sourceRect = view.bounds
activityViewController.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.down
UIApplication.shared.windows.first?.rootViewController?.present(activityViewController, animated: true, completion: nil)

2
我已经设置了这些弹出窗口的属性,应用程序不再崩溃,但视图也没有出现。 - soger

2

例如,对于iPad,您可以设置popoverPresentationControllerbarButtonItem

let activityViewController = UIActivityViewController(activityItems: ["Hello, world!", urlString], applicationActivities: nil)

if UIDevice.current.userInterfaceIdiom == .pad {
    activityViewController.popoverPresentationController?.barButtonItem = barButtonItem
}

self.present(activityViewController, animated: true)

1
设置为什么?在您的变量barButtonItem的示例中没有初始化。 - soger

0

嗯,我成功解决了iPad上的崩溃问题,只需检查选择器即可: let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)

        if activityVC.responds(to: #selector(getter: self.popoverPresentationController)) {
            activityVC.popoverPresentationController?.barButtonItem = sender
        }
        self.present(activityVC, animated: true, completion: nil)

0
对于iPad,将popoverPresentationController属性设置如下即可解决问题。
if UIDevice.current.userInterfaceIdiom == .pad {
    activityController.popoverPresentationController?.sourceView = self.webView
    activityController.popoverPresentationController?.sourceRect = self.accessibilityFrame
}

然后调用当前函数

self.viewController.present(activityController, animated: true)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接