web-dev-qa-db-fra.com

UIImagePickerController ne présentant pas dans iOS 8

Quelqu'un d'autre a-t-il un problème avec UIImagePickerController dans iOS 8? La méthode ci-dessous fonctionne parfaitement dans iOS 7 sur iPad, mais l'erreur suivante s'affiche lorsque j'exécute cette opération dans XCode 6 (version bêta 3 ou 4) lorsque j'essaie de présenter le sélecteur (dernière ligne). Si cela compte, la sélection du type de source provient d'un alertView présenté au même endroit.

Warning: Attempt to present <UIImagePickerController: 0x7c0ae400>  on <CAGUCreateContactViewController: 0x7bf61a00> which is already presenting (null)

Méthode pour ouvrir imagePicker.

- (void)openPhotoPicker:(UIImagePickerControllerSourceType)sourceType
{
    if ([UIImagePickerController isSourceTypeAvailable:sourceType]) {
        NSArray *availableMediaTypes = [UIImagePickerController availableMediaTypesForSourceType:sourceType];
        if ([availableMediaTypes containsObject:(NSString *)kUTTypeImage]) {
            UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
            imagePickerController.modalPresentationStyle = UIModalPresentationFullScreen;
            imagePickerController.sourceType = sourceType;
            imagePickerController.mediaTypes = @[(NSString *)kUTTypeImage];
            imagePickerController.delegate = self;

            self.imagePickerController = imagePickerController;

            if (sourceType == UIImagePickerControllerSourceTypeCamera) {
                [self presentViewController:self.imagePickerController animated:YES completion:nil];
            } else {                    
                if (self.popoverVC) {
                    [self.popoverVC dismissPopoverAnimated:YES];
                    self.popoverVC = nil;
                }

                self.popoverVC = [[UIPopoverController alloc] initWithContentViewController:imagePickerController];
                [self.popoverVC presentPopoverFromRect:self.nameAndPicCell.picture.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
            }
        }
    }
}
56
Dave

Je pense que cela est dû au fait que dans iOS 8, les vues d'alerte et les feuilles d'action sont réellement présentées aux contrôleurs de vue (UIAlertController). Ainsi, si vous présentez un nouveau contrôleur de vue en réponse à une action de UIAlertView, il est présenté pendant que UIAlertController est congédié. J'ai résolu le problème en retardant la présentation de la variable UIImagePickerController jusqu'à la prochaine itération du runloop, en procédant comme suit:

[[NSOperationQueue mainQueue] addOperationWithBlock:^{
    [self openPhotoPicker:sourceType];
}];

Cependant, le moyen approprié de résoudre ce problème consiste à utiliser la nouvelle API UIAlertController sur iOS 8 (c'est-à-dire, utilisez if ([UIAlertController class]) ... pour le tester). Ceci est juste une solution de contournement si vous ne pouvez pas utiliser la nouvelle API pour le moment.

108
Ben Lings

Je suis d'accord avec la détection de problème Ben Lings. Je suggérerais une solution plus simple au cas où vous utiliseriez UIActionSheet. J'ai simplement déplacé mon code qui réagit à la sélection de la feuille d'action à partir de: 

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex;
{
// my code
}

dans:

- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex;  // after animation
{
// my code
}

De cette façon, l'application garantit que le code sera exécuté APRÈS la fin de l'animation UIActionSheet.

UIAlertView ayant une méthode déléguée similaire:

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex;  // after animation
{
// my code
}

Je suppose qu'une solution similaire peut s'appliquer.

80
vedrano

Voici une solution qui a fonctionné pour moi

if([[[UIDevice currentDevice] systemVersion] floatValue]>=8.0)
{
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{

        [self presentViewController:cameraUI animated:NO completion:nil];
    }];

}
else{

    [controller presentViewController:cameraUI animated:NO completion:nil];
}

N'oubliez pas d'allouer cameraUI

UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;

Construire et aller!

12

J'étais confronté au même problème dans iOS 8 . Ensuite, j'ai consulté le journal des modifications de la dernière mise à jour pour iOS, à savoir 8.0.2 sur l'appareil.

Il est mentionné dans cette mise à jour que_

"Corrige un problème empêchant certaines applications d'accéder aux photos de la photothèque"

Alors testez votre application en utilisant XCode 6 sur un appareil avec la version iOS 8.0.2, elle fonctionnera correctement.

Cela m'a aidé, espérons la même chose pour vous.

Screen-shot of iOS 8.0.2 Update change log

8
Piyush Mathur
UIImagePickerController *imagePickerController= [[UIImagePickerController alloc] init];
[imagePickerController setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];

// image picker needs a delegate so we can respond to its messages
[imagePickerController setDelegate:self];
self.shouldCallViewWillAppear = NO;

if(IS_IOS8)
{
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        // Place image picker on the screen
        [self presentViewController:imagePickerController animated:YES completion:nil];
    }];
}
else
{
    [self presentViewController:imagePickerController animated:YES completion:nil];
}
4
Nirav Gadhiya

Vous pouvez ignorer le contrôleur de vue présenté (le cas échéant) en utilisant 

[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];

Cela a fonctionné pour moi.

3
Ritu

Tout ce que vous avez à faire est de rejeter ViewController déjà présenté:

if (self.presentedViewController) {
    [self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
}

[self openPhotoPicker:sourceType];

Si l'erreur persiste, mettez openPhotoPicker: dans le gestionnaire d'achèvement

2
Nikolay Krasnov

Sur iOS 8, vous devez utiliser la nouvelle API:

if (SYSTEM_VERSION_IOS_8) {
    self.imagePickerController.modalPresentationStyle = UIModalPresentationPopover;
    UIPopoverPresentationController *popPC = self.imagePickerController.popoverPresentationController;
    popPC.barButtonItem = self.popoverItem;
    popPC.permittedArrowDirections = UIPopoverArrowDirectionAny;
    [self presentViewController:self.imagePickerController animated:YES completion:nil]
}

Je vous recommande de regarder la session WWDC 2014 228 dans les contrôleurs de présentation latérale

1
Vito Ziv

J'ai eu beaucoup de peine à trouver une solution qui fonctionne à la fois sur iPad et iPhone, voici le code final dont certaines proviennent de commentaires d'autres personnes: commencer :) 

définitions:

__weak IBOutlet UIButton *attachButton;
UIImage *image;

action du bouton: 

    - (IBAction)doAttach:(id)sender {
    UIActionSheet *action = [[UIActionSheet alloc] initWithTitle:@"Select image from" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"From library",@"From camera", nil] ;
    [action showInView:self.view];
  }



#pragma mark - ActionSheet delegates

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if( buttonIndex == 1 ) {
        AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
        if(authStatus == AVAuthorizationStatusAuthorized)
        {
            NSLog(@"%@", @"You have camera access");
        }
        else if(authStatus == AVAuthorizationStatusDenied)
        {
            NSLog(@"%@", @"Denied camera access");

            [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
                if(granted){
                    NSLog(@"Granted access to %@", AVMediaTypeVideo);
                } else {
                    [self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
                    UIAlertController* alert = [UIAlertController alertControllerWithTitle:@“no camera access“
                                                                                   message: @“if you need to use camera in this application go to settings -> appName -> and turn on camera.”
                                                                            preferredStyle:UIAlertControllerStyleAlert];

                    UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@“ok” style:UIAlertActionStyleDefault
                                                                          handler:^(UIAlertAction * action) {
                                                                          }];
                    [alert addAction:defaultAction];

                    [self presentViewController:alert animated:YES completion:nil];


                    NSLog(@"Not granted access to %@", AVMediaTypeVideo);
                    return ;
                }
            }];
        }
        else if(authStatus == AVAuthorizationStatusRestricted)
        {
            [self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
            UIAlertController* alert = [UIAlertController alertControllerWithTitle:@“no camera access“
                                                                                   message: @“if you need to use camera in this application go to settings -> appName -> and turn on camera.”
                                                                            preferredStyle:UIAlertControllerStyleAlert];

            UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@“ok” style:UIAlertActionStyleDefault
                                                                  handler:^(UIAlertAction * action) {
                                                                  }];
            [alert addAction:defaultAction];

            [self presentViewController:alert animated:YES completion:nil];


            NSLog(@"%@", @"Restricted, normally won't happen");
        }
        else if(authStatus == AVAuthorizationStatusNotDetermined)
        {
            NSLog(@"%@", @"Camera access not determined. Ask for permission.");

            [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
                if(granted){
                    NSLog(@"Granted access to %@", AVMediaTypeVideo);
                } else {
                    NSLog(@"Not granted access to %@", AVMediaTypeVideo);
                    return ;
                }
            }];
        }
        else
        {
            [self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
            UIAlertController* alert = [UIAlertController alertControllerWithTitle:@“No camera access“
                                                                           message: @“error accusing camera”
                                                                    preferredStyle:UIAlertControllerStyleAlert];

            UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@“ok” style:UIAlertActionStyleDefault
                                                                  handler:^(UIAlertAction * action) {
                                                                  }];
            [alert addAction:defaultAction];

            [self presentViewController:alert animated:YES completion:nil];


            return;
            //NSLog(@"%@", @"Camera access unknown error.");
        }

        if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {


            UIImagePickerController *pickerView =[[UIImagePickerController alloc]init];
            pickerView.allowsEditing = YES;
            pickerView.delegate = self;
            pickerView.sourceType = UIImagePickerControllerSourceTypeCamera;


            if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {

                [ self.presentedViewController dismissViewControllerAnimated:YES completion:nil ];

                pickerView.modalPresentationStyle = UIModalPresentationPopover;
                UIPopoverPresentationController *popPC = pickerView.popoverPresentationController;
                popPC.sourceView = attachButton;
                popPC.permittedArrowDirections = UIPopoverArrowDirectionAny;
                [self presentViewController:pickerView animated:YES completion:nil];
            } else {
                [self presentModalViewController:pickerView animated:YES ];
            }
        }

    }else if( buttonIndex == 0 ) {

        ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
        switch (status) {
            case ALAuthorizationStatusRestricted:
            case ALAuthorizationStatusDenied:
            {
                [self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
                UIAlertController* alert = [UIAlertController alertControllerWithTitle:@“no access to library”
                                                                               message: @“if you wish to access photos in this app go to settings -> appName-> and turn on photos .”
                                                                        preferredStyle:UIAlertControllerStyleAlert];

                UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@“ok” style:UIAlertActionStyleDefault
                                                                      handler:^(UIAlertAction * action) {
                                                                      }];
                [alert addAction:defaultAction];

                [self presentViewController:alert animated:YES completion:nil];

            }
                break;

            default:
            {
                UIImagePickerController *pickerView = [[UIImagePickerController alloc] init];
                pickerView.allowsEditing = YES;
                pickerView.delegate = self;

                [pickerView setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];


                if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {

                    [ self.presentedViewController dismissViewControllerAnimated:YES completion:nil ];

                    pickerView.modalPresentationStyle = UIModalPresentationPopover;
                    UIPopoverPresentationController *popup = pickerView.popoverPresentationController;
                    popup.sourceView = attachButton;
                    popup.permittedArrowDirections = UIPopoverArrowDirectionAny;
                    [self presentViewController:pickerView animated:YES completion:nil];
                } else {
                    [self presentModalViewController:pickerView animated:YES ];
                }
            }
                break;
        }



    }
}

#pragma mark - PickerDelegates

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{

    [self dismissModalViewControllerAnimated:true];

    UIImage * img = [info valueForKey:UIImagePickerControllerEditedImage];
    image = img;

}
1
Omid S.

J'ai simplement fait ceci:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,
                                         (unsigned long)NULL), ^(void) {

    [self retractActivePopover];

    dispatch_async(dispatch_get_main_queue(), ^ {

        _activePopover=imagePickerPopover;

        UIBarButtonItem *callingButton = (UIBarButtonItem*) sender;

        [imagePickerPopover presentPopoverFromBarButtonItem:callingButton permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];

    });

});
1
Sebastian Dwornik

Voici une solution Xamarin. Ce qui a fonctionné pour moi a été d’ajouter mes actions à un gestionnaire d’événements rejeté.

this.btnPhoto.TouchUpInside += (sender, e) =>
{
    actionSheet = new UIActionSheet ("Add Photo");
    actionSheet.AddButton ("Take Photo");
    actionSheet.AddButton ("Select from Library");
    actionSheet.AddButton ("Cancel");
    actionSheet.DestructiveButtonIndex = -1; // red
    actionSheet.CancelButtonIndex = 3;  // black
    actionSheet.Clicked += delegate(object a, UIButtonEventArgs b)
    {
        actionSheet.Dismissed += (object aSender, UIButtonEventArgs dismissArgs) => 
        {
            switch (dismissArgs.ButtonIndex)
            {
                case 0:
                    showCamera ();
                    break;
                case 1:
                    showPhotoLibrary ();
                    break;
            }
        };
    };
    actionSheet.ShowInView (view);
};
0
Vincent

performSelector: withObject: afterDelay a résolu mon problème.

a également faitDismissWithButtonIndex faire le tour.

Max

0
masgar