2014-09-03 129 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) 
}