UIActivityViewController在ios8 ipad上崩溃

我目前正在用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.

我使用以下代码用于iPhone和iPad的iOS 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有什么变化吗?我查过了,但在这上面什么也没找到

99909 次浏览

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

  • < a href = " https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIPopoverPresentationController_class/index.html / / apple_ref / occ / instp / UIPopoverPresentationController /把" >把< / >
  • < a href = " https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIPopoverPresentationController_class/index.html / / apple_ref / occ instp / UIPopoverPresentationController / sourceView”> sourceView < / >
  • < a href = " https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIPopoverPresentationController_class/index.html / / apple_ref / occ instp / UIPopoverPresentationController / sourceRect”> sourceRect < / >

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

if ( [activityViewController respondsToSelector:@selector(popoverPresentationController)] ) {
// iOS8
activityViewController.popoverPresentationController.sourceView =
parentView;
}
我找到了这个解决方案 首先,呈现弹出窗口的视图控制器应该实现<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;
}

同样的问题出现在我的项目中,然后我找到了解决方案,在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];
}

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

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

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

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

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

在.m文件中的下一个:yourUIActivityViewController.popoverPresentationController.barButtonItem = self.barButtonItem;

迅速:

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

如果你是在iPad上使用swift进行开发,那么你就得小心了,它在调试时可以正常工作,但在发布时就会崩溃。为了使它与testFlight和AppStore一起工作,禁用使用-none发布swift的优化。

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

修复了斯威夫特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)
}

我最近在Swift 2.0中遇到了这个确切的问题(最初的问题),其中UIActivityViewController在iphone上运行良好,但在模拟ipad时导致崩溃。

我只是想在这里补充一点,至少在Swift 2.0中,你不需要if语句。你可以让popoverPresentationController是可选的。

作为一个快速题外,公认的答案似乎是说,你可以只有一个sourceView,只有一个sourceRect,或只是一个barButtonItem,但根据苹果的UIPopoverPresentationController文档,你需要下列之一:

  • 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,那么提到它的两行代码基本上会被忽略。

有点好,所有你需要做的,使它工作的ipad只是添加两行代码,或者只是一个如果你使用barButtonItem!

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


}
}

我看到很多人在使用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上将为nil,因此vc.popoverPresentationController?行在iPhone上将不做任何事情。

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)

斯威夫特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 4下面的代码工作在iphone和ipad。 根据文档

.

对于给定的设备习惯用法,使用适当的方法来呈现和解散视图控制器是你的责任。在iPad上,你必须在弹出窗口中显示视图控制器。在其他设备上,你必须以模态方式呈现它。

 let activityViewController = UIActivityViewController(activityItems: activityitems, applicationActivities: nil)


if UIDevice.current.userInterfaceIdiom == .pad {


if activityViewController.responds(to: #selector(getter: UIViewController.popoverPresentationController)) {
activityViewController.popoverPresentationController?.sourceView = self.view
}
}


self.present(activityViewController, animated: true, completion: nil)

解决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];
}
}

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

activityViewController.popoverPresentationController?.barButtonItem = sender

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

activityViewController.popoverPresentationController?.sourceView = sender
activityViewController.popoverPresentationController?.sourceRect = sender.bounds

从文档到UIPopoverPresentationController:

var barButtonItem: UIBarButtonItem? { get set }

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

我使用Swift 5。 当我在iPad上的应用程序中点击“分享按钮”时,我也遇到了同样的问题。找到了这个解。 步骤1:将“view”对象(在对象库中搜索“UIView”)添加到Main.storyboard。 步骤2:在ViewController.swift中创建一个@IBOutlet,并指定任何名称(例如:view1)

步骤3:添加上述名称(例如:view1)作为sourceView。这是我的“分享按钮”动作。

@IBAction func Share(_ sender: Any) {
let activityVC = UIActivityViewController(activityItems: ["www.google.com"], applicationActivities: nil)
activityVC.popoverPresentationController?.sourceView = view1


self.present(activityVC, animated: true, completion: nil)




}

我对swift很陌生,在这个问题上耽搁了一个星期。希望这能帮助到一些人。分享这个解。

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

只是作为参考。

我分享以下代码,这一个使用Swift 5.0。此外,它还避免了弃用的窗口。

UIApplication.shared.windows.first ? .rootViewController !。present(actiycontroller, animated: true, completion: nil)

代码片段如下:

let activityController = UIActivityViewController(activityItems: [activityItem], applicationActivities: nil)


let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
let window = windowScene?.windows.first


if UIDevice.current.userInterfaceIdiom == .pad{
activityController.popoverPresentationController?.sourceView = window
activityController.popoverPresentationController?.sourceRect = CGRect(x:  UIScreen.main.bounds.width / 3, y:  UIScreen.main.bounds.height / 1.5, width: 400, height: 400)
}


window?.rootViewController!.present(activityController, animated: true)

它已经在iPhone和iPad上进行了测试。

希望它能帮助到一些人。

干杯!