web-dev-qa-db-fra.com

Swift UIAlertController -> ActionSheet iPad iOS8 se bloque

je rencontre actuellement de gros problèmes avec mon ActionSheet. Sur iPhone, cela fonctionne très bien, mais sur iPad, il ne fait que planter.

Je crée un nouveau projet avec un seul bouton

import UIKit

extension ViewController : UIActionSheetDelegate {

    func actionSheet(actionSheet: UIActionSheet, didDismissWithButtonIndex buttonIndex: Int) {

        if actionSheet.tag == 0 {
            if buttonIndex == 1 {
                // doing something for "product page"
            } else if (buttonIndex == 2) {
                // doing something for "video"
            }
        }
    }

}

class ViewController: UIViewController, UIActionSheetDelegate {
    @IBAction func test(sender: AnyObject) {

        let systemVersion: NSInteger = (UIDevice.currentDevice().systemVersion as NSString).integerValue
        if systemVersion < 8 {
            // iOS7:
            let action:UIActionSheet = UIActionSheet(title: "Change Map Type", delegate: self, cancelButtonTitle: "Back", destructiveButtonTitle: nil, otherButtonTitles: "Product Page", "Video")
            action.tag = 0
            action.showInView(self.view)
        } else {
            // iOS8:
            let alertController: UIAlertController = UIAlertController(title: "Change Map Type", message: nil, preferredStyle: UIAlertControllerStyle.ActionSheet)
            let cancelAction: UIAlertAction = UIAlertAction(title: "Back", style: UIAlertActionStyle.Cancel, handler: nil)
            let button1action: UIAlertAction = UIAlertAction(title: "Product Page", style: UIAlertActionStyle.Default, handler: { (action: UIAlertAction!) -> () in
                // doing something for "product page"
            })
            let button2action: UIAlertAction = UIAlertAction(title: "Video", style: UIAlertActionStyle.Default, handler: { (action: UIAlertAction!) -> () in
                // doing something for "video"
            })
            alertController.addAction(cancelAction)
            alertController.addAction(button1action)
            alertController.addAction(button2action)

            self.presentViewController(alertController, animated: true, completion: nil)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

}

Comme je l'ai dit sur l'iphone, cela fonctionne, mais si je clique sur le bouton sur iPad, l'application se bloque

2014-09-25 14: 54: 52.784 test [9541: 1970048] * Application de terminaison en raison de exception non interceptée 'NSGenericException', motif: 'Votre application a a présenté un UIAlertController () de style UIAlertControllerStyleActionSheet. Le modalPresentationStyle de Un UIAlertController avec ce style est UIModalPresentationPopover. Vous doit fournir des informations de localisation pour ce popover par le biais de l'alerte popoverPresentationController du contrôleur. Vous devez fournir soit un sourceView et sourceRect ou un barButtonItem. Si cette information est pas connu lorsque vous présentez le contrôleur d’alertes, vous pouvez le fournir en la méthode UIPopoverPresentationControllerDelegate -prepareForPopoverPresentation. ' * Pile d’appel du premier jet: (0 CoreFoundation 0x00613df6 exceptionPreprocess + 182 1 libobjc.A.dylib
0x01fdaa97 objc_exception_throw + 44 2 UIKit
0x0164da37 - [UIPopoverPresentationController presentationTransitionWillBegin] + 3086 3 UIKit
0x00f54f75 __71- [UIPresentationController _initViewHierarchyForPresentationSuperview:] _ block_invoke + 1666 4 UIKit 0x00f53554 __56- [UIPresentationController runTransitionForCurrentState] _block_invoke + 226 5 UIKit
0x00f8721b __40 + [UIViewController _scheduleTransition:] _ block_invoke + 18 6 UIKit 0x00e4d62e ___afterCACommitHandler_block_invoke + 15 7 UIKit 0x00e4d5d9 _applyBlockToCFArrayCopiedToStack + 415 8 UIKit
0x00e4d3ee _afterCACommitHandler + 545 9 CoreFoundation
0x00536fbe __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION
+ 30 10 CoreFoundation 0x00536f00 __CFRunLoopDoObservers. + 400 11 CoreFoundation 0x0052c93a __CFRunLoopRun + 1226 12 CoreFoundation 0x0052c1ab CFRunLoopRunSpecific + 443 13 CoreFoundation
0x0052bfdb CFRunLoopRunInMode + 123 14 GraphicsServices
0x0438424f GSEventRunModal + 192 15 GraphicsServices
0x0438408c GSEventRun + 104 16 UIKit
0x00e23e16 UIApplicationMain + 1526 17 test
0x00085e9e top_level_code + 78 18 test
0x00085edb principal + 43 19 libdyld.dylib
0x0273eac9 début + 1 20 ???
0x00000001 0x0 + 1) libc ++ abi.dylib: se terminant par uncaught exception de type NSException

Le projet peut être trouvé à l’adresse https://www.dropbox.com/s/54jqd8nsc67ll5g/test.zip?dl=0 à télécharger et à essayer.

53
Fabian Boulegue

Le message d'erreur vous indique que vous devez attribuer à l'emplacement popoverPresentationController du contrôleur d'alerte un emplacement lui permettant de se positionner correctement. C'est facile à faire - il suffit de vérifier s'il y a un contrôleur popover et d'ajouter l'expéditeur comme source.

Si votre bouton est une UIBarButtonItem:

if let popoverController = alertController.popoverPresentationController {
    popoverController.barButtonItem = sender
}
self.presentViewController(alertController, animated: true, completion: nil)

Autrement:

if let popoverController = alertController.popoverPresentationController {
    popoverController.sourceView = sender
    popoverController.sourceRect = sender.bounds
}
self.presentViewController(alertController, animated: true, completion: nil)
145
Nate Cook

essaye ça 

alertController.popoverPresentationController?.sourceView = self.view
7
Beslan Tularov

Nate Cook a tout à fait raison, mais je le ferais afin de détecter s'il s'agit d'un iPad ou d'un iPhone.

Ceci est pour barButtonItem:

if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad ){

            if let currentPopoverpresentioncontroller = alertController.popoverPresentationController{
                currentPopoverpresentioncontroller.barButtonItem = sender as! UIBarButtonItem
                currentPopoverpresentioncontroller.permittedArrowDirections = UIPopoverArrowDirection.down;
                self.present(alertController, animated: true, completion: nil)
            }
        }else{
            self.present(alertController, animated: true, completion: nil)
        }
2
Tarvo Mäesepp

var actionSheet = UIAlertController (titre: "Choisissez une caméra ou une bibliothèque de photos", message: "", preferredStyle: .actionSheet)

    if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad ){
        actionSheet = UIAlertController(title: "Please Select Camera or Photo Library", message: "", preferredStyle: .alert)
    }

    actionSheet.addAction(UIAlertAction(title: "Upload a Photo", style: .default, handler: { (UIAlertAction) in
        self.openPhotoLibrary()
    }))
    actionSheet.addAction(UIAlertAction(title: "Take a Photo", style: .default, handler: { (UIAlertAction) in
        self.openCamera()
    }))
    actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
    self.present(actionSheet, animated: true, completion: nil)
1
aakash tandukar

Si vous souhaitez le présenter au centre sans flèches sur les iPads [ Swift 3+ ]:

    if let popoverController = alertController.popoverPresentationController {
        popoverController.sourceView = self.view
        popoverController.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
        popoverController.permittedArrowDirections = []
    }
    self.present(alertController, animated: true, completion: nil)
0
Mohit Singh

Si quelqu'un utilise sender: UITapGestureRecognizer cela pourrait être utile.

@objc func popupSettings(sender : UITapGestureRecognizer) {
    .....
    if let popoverPresentationController = alert.popoverPresentationController {
        popoverPresentationController.sourceView = self.view
        popoverPresentationController.sourceRect = CGRect(Origin: sender.location(in: self.view), size: CGSize(width: 1.0, height: 1.0))
    }
    self.present(alert, animated: true, completion: nil)
}
0
Shahin Mammadzada

Si vous voulez afficher votre alerte au centre et sans flèche, j'ai essayé, cela fonctionne sur iOS 11.2

Version Swift 4.2:

let actionSheet = UIAlertController ......
if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad ){

        if let currentPopoverpresentioncontroller = actionSheet.popoverPresentationController{
            currentPopoverpresentioncontroller.permittedArrowDirections = []
            currentPopoverpresentioncontroller.sourceRect = CGRect(x: (self.view.bounds.midX), y: (self.view.bounds.midY), width: 0, height: 0)
            currentPopoverpresentioncontroller.sourceView = self.view
            self.present(actionSheet, animated: true, completion: nil)
        }
    }else{
        self.present(actionSheet, animated: true, completion: nil)
    }

Version Objective C:

UIAlertController* actionSheet 
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    NSArray *empty;
    UIPopoverPresentationController *currentPopOverPresentationController = [actionSheet popoverPresentationController];
    currentPopOverPresentationController.permittedArrowDirections = empty;
    currentPopOverPresentationController.sourceRect = CGRectMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds), 0, 0);
    currentPopOverPresentationController.sourceView = self.view;

    [self presentViewController:actionSheet animated:YES completion:nil];
}else{
    [self presentViewController:actionSheet animated:YES completion:nil];
}
0
Emre Agbal