it-swarm.com.de

UIActivityViewController stürzt auf iOS 8 iPads ab

Ich teste derzeit meine App mit Xcode 6 (Beta 6). UIActivityViewController funktioniert gut mit iPhone-Geräten und Simulatoren, stürzt jedoch mit iPad-Simulatoren und -Geräten (iOS 8) mit folgenden Protokollen ab

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

Ich verwende den folgenden Code für iPhone und iPad sowohl für iOS 7 als auch für 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];

Ich bekomme einen ähnlichen Absturz in einer meiner anderen App. Kannst du mich bitte führen? hat sich mit UIActivityViewController in iOS 8 etwas geändert? Ich habe nachgesehen, aber ich habe nichts dazu gefunden

267
Bhumit Mehta

Auf dem iPad wird der Aktivitätsansicht-Controller mit dem neuen UIPopoverPresentationController als Popover angezeigt. Dazu müssen Sie einen Ankerpunkt für die Präsentation des Popovers mit einer der drei folgenden Eigenschaften angeben:

Um den Ankerpunkt festzulegen, müssen Sie einen Verweis auf den UIPopoverPresentationController des UIActivityController erhalten und eine der Eigenschaften wie folgt festlegen:

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

Das gleiche Problem ist zu meinem Projekt gekommen, dann habe ich die Lösung gefunden, um den UIActivityViewController in iPad zu öffnen, müssen wir UIPopoverController

Hier ist ein Code für die Verwendung in iPhone und 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];
}

Für Swift 4.2

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 = [ UIActivity.ActivityType.airDrop]

        //vwShareVideo is a view from which you want to show popover in iPad

        if UIDevice.current.userInterfaceIdiom == .pad {
            activityViewController.popoverPresentationController?.sourceView = self.vwShareVideo
            activityViewController.popoverPresentationController?.permittedArrowDirections = .down
            activityViewController.popoverPresentationController?.sourceRect = self.vwShareVideo.bounds
        }

        self.present(activityViewController, animated: true, completion: nil)
    }
175
Hardik Thakkar

Dieses genaue Problem (die ursprüngliche Frage) war kürzlich in Swift 2.0 aufgetreten, wobei UIActivityViewController für iPhones einwandfrei funktionierte, jedoch beim Simulieren von iPads Abstürze verursachte. 

Ich möchte diesem Thread der Antworten hier nur hinzufügen, dass Sie zumindest in Swift 2.0 keine if-Anweisung benötigen. Sie können die popoverPresentationController einfach optional machen. 

Nebenbei gesagt, scheint die akzeptierte Antwort zu sein, dass Sie nur eine sourceView, nur eine sourceRect oder nur ein barButtonItem haben könnten, aber laut Apples Dokumentation für UIPopoverPresentationController benötigen Sie Folgendes:

  • barButtonItem
  • sourceView und sourceRect

Das spezielle Beispiel, an dem ich gerade gearbeitet habe, ist unten, wo ich eine Funktion erstelle, die eine UIView (für sourceView und sourceRect) und String (das einzige activityItem von UIActivityViewController) aufnimmt. 

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

Dieser Code funktioniert auf iPhone und iPad (und sogar tvOS, glaube ich). Wenn das Gerät popoverPresentationController nicht unterstützt, werden die beiden Codezeilen, die es erwähnen, im Wesentlichen ignoriert. 

Ein bisschen schön, dass Sie alles, was Sie tun müssen, damit es für iPads funktioniert, nur zwei Zeilen Code hinzufügen muss, oder nur eine, wenn Sie ein BarButtonItem verwenden!

36
Galen

Ich sehe eine Menge Leute, die iPhone/iPad usw. mit Swift-Code verschlüsseln.

Dies ist nicht erforderlich, Sie müssen die Sprachfunktionen verwenden. Im folgenden Code wird davon ausgegangen, dass Sie ein UIBarButtonItem verwenden und auf beide iPhone und iPad funktionieren. 

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

Beachten Sie, dass es keine If-Anweisungen oder andere verrückte Dinge gibt. Das optionale Auspacken ist auf dem iPhone gleich Null, sodass die Zeile vc.popoverPresentationController? auf iPhones nichts tut.

16

Lösung mit Xamarin.iOS.

In meinem Beispiel mache ich eine Bildschirmaufnahme, produziere ein Bild und erlaube dem Benutzer, das Bild zu teilen. Das Popup auf dem iPad wird ungefähr in der Mitte des Bildschirms angezeigt.

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
ben

Swift, iOS 9/10 (nachdem UIPopoverController veraltet)

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

Um dieses Problem für das iPad zu beheben, ist es am besten, so zu tun, wie ich es gefunden habe.

    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
Niklas

Fix für 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
datayeah

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
Daniel McLean

Schnell:

    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
kalpeshdeo

Wenn Sie UIActivityViewController anzeigen, wenn Sie auf eine UIBarButtonItem klicken, verwenden Sie den folgenden Code:

activityViewController.popoverPresentationController?.barButtonItem = sender

Andernfalls verwenden Sie den folgenden Code, wenn Sie ein anderes Steuerelement verwenden, z. B. eine UIButton.

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

Von der Dokumentation zur UIPopoverPresentationController:

var barButtonItem: UIBarButtonItem? { get set }

Weisen Sie dieser Eigenschaft einen Wert zu, um das Popover mit dem angegebenen Bar-Schaltflächenelement zu verankern. Wenn der Pfeil des Popovers angezeigt wird, zeigt er auf das angegebene Element. Alternativ können Sie den Ankerstandort für das Popover mithilfe der Eigenschaften sourceView und sourceRect angeben.

2
DronPop

Lösung für Objective-C und mit 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];
        }
    }
1
kurono267

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
ingconti

Ich habe den nächsten Code ausprobiert und es funktioniert:

fügen Sie zuerst ein Balkenschaltflächenelement in Ihren View Controller ein und erstellen Sie dann ein IBOutlet:

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

als nächstes in der .m-Datei: yourUIActivityViewController.popoverPresentationController.barButtonItem = self.barButtonItem;

0
Mike

In Swift 4 funktioniert folgender Code in iphone und ipad . Nach Dokumentation 

Es liegt in Ihrer Verantwortung, den View-Controller mit den geeigneten Mitteln für die angegebene Geräte-ID zu präsentieren und zu entfernen. Auf dem iPad müssen Sie den View-Controller in einem Popover präsentieren. Auf anderen Geräten müssen Sie es modal präsentieren.

 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)
0
Imran Khan

Ich habe diese Lösung gefunden Zunächst sollte Ihr View-Controller, der das Popover präsentiert, das Protokoll <UIPopoverPresentationControllerDelegate> implementieren.

Als Nächstes müssen Sie den Delegierten von popoverPresentationController festlegen.

Fügen Sie diese Funktionen hinzu:

- (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
Mongo db