UIActivityViewController en panne sur iOS 8 iPad

Je teste actuellement mon application avec Xcode 6 (Beta 6). UIActivityViewController fonctionne bien avec les appareils et simulateurs iPhone, mais tombe en panne avec les simulateurs et les périphériques iPad (iOS 8) avec les journaux suivants

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

J’utilise le code suivant pour iPhone et iPad à la fois pour iOS 7 et 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]; 

Je reçois également un crash similaire dans une autre application. Pouvez-vous me guider s’il vous plaît? quelque chose a changé avec UIActivityViewController dans iOS 8? J’ai vérifié mais je n’ai rien trouvé à ce sujet

    Sur l’iPad, le contrôleur de vue d’activité sera affiché sous forme de pop-up à l’aide du nouveau UIPopoverPresentationController . Il vous faudra spécifier un point d’ancrage pour la présentation du popover à l’aide de l’une des trois propriétés suivantes:

    • barButtonItem
    • sourceView
    • sourceRect

    Pour spécifier le point d’ancrage, vous devez obtenir une référence à l’UIPopoverPresentationController de l’UIActivityController et définir l’une des propriétés comme suit:

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

    Le même problème est venu à mon projet alors j’ai trouvé la solution pour ouvrir le UIActivityViewController dans iPad, nous devons utiliser UIPopoverController

    Voici un code pour l’utiliser sur iPhone et iPad

     //to attach the image and text with sharing UIImage *image=[UIImage imageNamed:@"giraffe.png"]; NSSsortingng *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]; } 

    Pour rapide

     let imageURL: URL = URL(ssortingng: product.images[0].fullImageUrlSsortingng)! let objectsToShare: [AnyObject] = [imageURL as AnyObject] let activityViewController = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil) activityViewController.popoverPresentationController?.sourceView = self.view activityViewController.excludedActivityTypes = [.airDrop] self.present(activityViewController, animated: true, completion: nil) 

    Je rencontrais ce problème précis récemment (la question initiale) dans Swift 2.0, où UIActivityViewController fonctionnait bien pour les iPhones, mais provoquait des plantages lors de la simulation des iPad.

    Je veux juste append à ce fil des réponses ici que, au moins dans Swift 2.0, vous n’avez pas besoin d’une instruction if. Vous pouvez simplement rendre le popoverPresentationController facultatif.

    En un clin d’œil, la réponse acceptée semble être que vous pourriez avoir juste un sourceView, juste un sourceRect, ou juste un barButtonItem, mais selon la documentation d’ Apple pour UIPopoverPresentationController, vous avez besoin de l’un des éléments suivants:

    • barButtonItem
    • sourceView et sourceRect

    L’exemple particulier sur lequel je travaillais est ci-dessous, où je crée une fonction qui prend en charge UIView (pour le sourceView et le sourceRect) et Ssortingng (le seul élément de l’activité de UIActivityViewController).

     func presentActivityViewController(sourceView: UIView, activityItem: Ssortingng ) { let activityViewController = UIActivityViewController(activityItems: [activityItem], applicationActivities: []) activityViewController.popoverPresentationController?.sourceView = sourceView activityViewController.popoverPresentationController?.sourceRect = sourceView.bounds self.presentViewController(activityViewController, animated: true, completion: nil) } 

    Ce code fonctionne sur iPhone et iPad (et même sur tvOS je pense) – si l’appareil ne supporte pas popoverPresentationController , les deux lignes de code qui le mentionnent sont essentiellement ignorées.

    Un peu sympa que tout ce que vous devez faire pour que cela fonctionne pour les iPads est juste append deux lignes de code, ou juste une si vous utilisez un barButtonItem!

    Je vois beaucoup de gens coder en dur iPhone / iPad, etc. tout en utilisant le code Swift.

    Ce n’est pas nécessaire, vous devez utiliser les fonctionnalités du langage. Le code suivant suppose que vous utiliserez un UIBarButtonItem et fonctionnera sur iPhone et 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) } 

    Remarquez qu’il n’y a pas de déclaration If ou toute autre chose folle. Le déballage optionnel sera nul sur iPhone, alors la ligne vc.popoverPresentationController? ne fera rien sur les iPhones.

    Solution utilisant Xamarin.iOS.

    Dans mon exemple, je fais une capture d’écran, produisant une image et permettant à l’utilisateur de partager l’image. La fenêtre contextuelle de l’iPad est placée à peu près au milieu de l’écran.

     var activityItems = new NSObject[] { image }; var excludedActivityTypes = new NSSsortingng[] { 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 NSSsortingng("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); 

    Swift, iOS 9/10 (après la suppression de 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) 

    Dans Swift pour corriger cela pour iPad, le meilleur moyen est de faire comme cela, j’ai trouvé.

      let things = ["Things to share"] let avc = UIActivityViewController(activityItems:things, applicationActivities:nil) avc.setValue("Subject title", forKey: "subject") avc.completionWithItemsHandler = { (s: Ssortingng!, 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 } 

    Correction pour Swift 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 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) } 

    Rapide:

      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) 

    J’ai trouvé cette solution Tout d’abord, votre contrôleur de vue qui présente le popover doit implémenter le protocole .

    Ensuite, vous devrez définir le popoverPresentationController de popoverPresentationController .

    Ajoutez ces fonctions:

     - (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 isEqualToSsortingng:@"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; } 

    J’ai essayé le code suivant et ça marche:

    placez d’abord un élément de barre dans votre View Controller, puis créez un IBOutlet:

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

    next dans le fichier yourUIActivityViewController.popoverPresentationController.barButtonItem = self.barButtonItem; : yourUIActivityViewController.popoverPresentationController.barButtonItem = self.barButtonItem;

    Pour Swift 2.0. J’ai trouvé que cela fonctionne si vous essayez d’ancrer le popover à un bouton de partage sur iPad. Cela suppose que vous avez créé un sharepoint vente pour le bouton Partager dans votre barre d’outils.

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

    Soyez prudent si vous développez pour iPad en utilisant swift, cela fonctionnera bien dans le débogage, mais se plantera dans la version. Pour qu’il fonctionne avec testFlight et AppStore, désactivez l’optimisation pour l’utilisation rapide de -none pour la publication.