Uiactivityviewcontroller se bloque sur iOS 8 iPads

Je teste actuellement mon application avec Xcode 6 (Beta 6). UIActivityViewController fonctionne bien avec les appareils et les simulateurs iPhone, mais se bloque avec les simulateurs et les appareils iPad (iOS 8) avec les journaux suivants

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

J'utilise le code suivant pour iPhone et iPad pour iOS 7 ainsi que pour 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 l'une de mes autres applications. Pouvez-vous svp me guider ? quelque chose a-t-il changé avec UIActivityViewController dans iOS 8? J'ai vérifié mais je n'ai pas trouvé quelque chose à ce sujet

260
demandé sur Fabian N. 2014-09-03 16:15:10

15 réponses

Sur iPad, le contrôleur de vue d'activité sera affiché en tant que popover en utilisant le nouveau UIPopoverPresentationController , Il nécessite que vous spécifiez un point d'ancrage pour la présentation du popover en utilisant l'une des trois propriétés suivantes:

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

if ( [activityViewController respondsToSelector:@selector(popoverPresentationController)] ) { 
// iOS8
 activityViewController.popoverPresentationController.sourceView =
parentView;
 }
437
répondu mmccomb 2015-07-30 05:51:25

Même problème est arrivé à mon projet, puis j'ai trouvé la solution pour ouvrir la UIActivityViewController dans iPad, nous devons utiliser UIPopoverController

Voici un code pour l'utiliser dans iPhone et iPad à la fois

//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];
}

Pour swift

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 = [.airDrop]
self.present(activityViewController, animated: true, completion: nil)
170
répondu Hardik Thakkar 2018-06-25 12:22:02

Je rencontrais ce problème exact récemment (la question originale) dans Swift 2.0, où UIActivityViewController fonctionnait bien pour les iPhones, mais provoquait des plantages lors de la simulation d'iPads.

Je veux juste ajouter à ce fil de 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 bref, la réponse acceptée semble dire 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 un UIView (pour sourceView et sourceRect) et String (le seul activityItem de UIActivityViewController).

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

Ce code fonctionne sur iPhone et iPad (et même tvOS je pense) -- si le périphérique ne prend pas en charge popoverPresentationController, les deux lignes de code qui le mentionnent sont essentiellement ignoré.

Un peu agréable que tout ce que vous devez faire pour le faire fonctionner pour iPads est juste ajouter deux lignes de code, ou juste une si vous utilisez un barButtonItem!

35
répondu Galen 2016-01-04 17:02:33

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

Ce n'est pas nécessaire, vous devez utiliser les fonctionnalités de langue. Le code suivant suppose que vous utiliserez un UIBarButtonItem et fonctionnera sur à la fois 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 comment il n'y a pas de déclarations If ou toute autre chose folle. Le déballage optionnel sera nul sur iPhone, donc la ligne vc.popoverPresentationController? ne fera rien sur les iPhones.

16
répondu Martin Marconcini 2016-01-22 01:42:27

Solution utilisant Xamarin.iOS.

Dans mon exemple, j'ai fais une capture d'écran, produisant une image, et permettant à l'utilisateur de partager l'image. Le pop-up sur l'iPad est placé au milieu de l'écran.

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);
10
répondu ben 2014-12-02 13:15:22

Swift, iOS 9/10 (après uipopovercontroller obsolète)

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)
6
répondu MPaulo 2016-08-10 04:14:20

Dans Swift pour résoudre ce problème pour iPad, la meilleure façon est de faire comme ceci que j'ai trouvé.

    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
    }
5
répondu Niklas 2015-06-29 17:01:46

Correctif 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)
    }
4
répondu datayeah 2015-10-23 00:03:35

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)
}
4
répondu Daniel McLean 2017-02-19 19:17:55

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)

    }
3
répondu kalpeshdeo 2015-06-06 18:50:35

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)
1
répondu ingconti 2015-07-16 06:20:42

J'ai trouvé cette solution Tout d'abord, votre contrôleur de vue qui présente le popover devrait implémenter le protocole <UIPopoverPresentationControllerDelegate>.

Ensuite, vous devrez définir le délégué 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 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;
}
0
répondu Mongo db 2014-10-07 11:06:26

J'ai essayé le code suivant et ça fonctionne:

Mettez D'abord un élément de bouton de barre dans votre contrôleur de vue ensuite, créez un IBOutlet:

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

Suivant dans le .m fichier: yourUIActivityViewController.popoverPresentationController.barButtonItem = self.barButtonItem;

0
répondu Mike 2015-04-10 09:35:39

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éé une sortie 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)
        }

    }
}
-1
répondu iosdevlangley 2016-01-14 19:04:20

Soyez prudent si vous développez pour iPad en utilisant swift, il fonctionnera bien dans le débogage, mais Plantera dans la version. Pour le faire fonctionner avec TestFlight et AppStore, désactivez l'optimisation pour swift en utilisant -none pour la version.

-5
répondu ingconti 2015-09-15 07:07:45