5

I'm using the following code to show a UIImagePickerController to take a picture:

UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
[imagePicker setDelegate:self];    
[imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera];
[self presentViewController:imagePicker animated:YES completion:nil];

Note: self is a UIViewController embedded inside a Container View, which itself takes part in a UINavigationController

And I have also implemented the following methods:

-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];  
    [self.imgProfile setImage:image];   
    [self dismissViewControllerAnimated:YES completion:nil];    
}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
    [self dismissViewControllerAnimated:YES completion:nil];
}

When I either choose the picture taken or cancel it, the UIImagePickerController goes away, but also the main view disappears! With a Fade to Black.

I'm coding for iOS7 on an iPad only app, in case it has anything to do with it.

Here is a video that shows the problem. Excuse the blur, but it is under an NDA.

http://www.youtube.com/watch?v=sIaPyRlIqyE

Jan
  • 2,462
  • 3
  • 31
  • 56
  • Try calling `dismissViewControllerAnimated...` on `picker` instead of `self`. – rmaddy Oct 03 '13 at 03:27
  • @rmaddy Tried that already. Same thing happens. – Jan Oct 03 '13 at 03:32
  • Is this problem on an iPad or iPhone? – rmaddy Oct 03 '13 at 03:37
  • @rmaddy iPad. Didn't try on iPhone since it's an iPad only app. I changed the tags to show that. – Jan Oct 03 '13 at 04:04
  • In your code, what is `self` embedded in? A split view controller? A tabbar controller? Try presenting the image picker from the root view controller of the app. – rmaddy Oct 03 '13 at 04:08
  • @rmaddy self is a UIViewController embedded inside a Container View. How could I present it directly in the root controller from where it is now? – Jan Oct 03 '13 at 04:19
  • Access the root view controller from `[UIApplication sharedApplication].keyWindow.rootViewController`. – rmaddy Oct 03 '13 at 05:06
  • @rmaddy Same thing :( I don't understand... It's like for some reason it's dismissing all the ViewControllers apart from one. – Jan Oct 03 '13 at 05:24

7 Answers7

14

I've encountered the same issue under iOS7, and the only solution I've found is do to as follows;

When presenting the picker from your VC ;

UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeMovie, nil];

[self addChildViewController:picker] ;

[picker didMoveToParentViewController:self] ;

[self.view addSubview:picker.view] ;

Then, when handling the picker delegates - instead of dismissModal, use ;

[picker.view removeFromSuperview] ;
[picker removeFromParentViewController] ;

All you lose is the animated present/dismiss - other than that, all should be well.

  • Can someone explain why the above code works in 8.1 and why does it not work properly < 8? I was using dismissModal and since upgrading to ios 8 my app has been broken when using the camera. BTW This did fix my problem and thank you! – tg2007 Feb 20 '15 at 19:00
5

Try setting your image picker's .modalPresentationStyle to either .OverCurrentContext or .OverFullScreen:

Alternately:

viewController.definesPresentationContext = true
imagePicker.modalPresentationStyle = .CurrentContext OR .FullScreen

The point being that the relationship between those two properties needs to be preserved as such: if false then .OverCurrentContext, if true then .CurrentContext

In my case, my view controller's .definesPresentationContext was defaulting to false, so I used the first option.

See documentation for some insight.

g.Rapido
  • 147
  • 1
  • 9
3

You should dismiss the picker, not your view (self) and be sure to add these:

<UINavigationControllerDelegate, UIImagePickerControllerDelegate>

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

UIImage *chosenImage = info[UIImagePickerControllerEditedImage];
self.imageView.image = chosenImage;

[picker dismissViewControllerAnimated:YES completion:NULL];

}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {

[picker dismissViewControllerAnimated:YES completion:NULL];

}
Gili Ariel
  • 572
  • 1
  • 6
  • 18
1

When the UIImagePickerController officially dismisses, it triggers the following methods on whatever VC is immediately behind it in the navigation stack:

- viewWillAppear
- viewDidAppear
- viewDidLayoutSubviews
a bunch of other methods having to do with basic VC lifecycle.

In my case, I wasn't presenting the topmost VC using the presentViewController: method. I was instantiating it as a child of the root VC and doing some custom animations. I was doing most of this work in the -viewDidLayoutSubviews method. Part of this work was specifying that the frame of my child view in an off-screen position.

So, when I animated my child view onto the screen, presented the camera, and then dismissed it, the app eventually triggered the -viewDidLayoutSubviews on my rootVC, which moved my childVC off-screen.

So, I guess the answer is to make sure that the initial VC setup code can only be triggered once (use something like Bool setupHasAlreadyHappenedOnce before laying everything out).

Gazzini
  • 728
  • 8
  • 19
0

It's recommended to use UIPopOver while you're opening the camera roll to iPad like this so give it a try hope it helps you.

#pragma mark
#pragma mark - Image Picker
-(IBAction)onClickTakePhoto:(id)sender
{
    if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
    {

        imagePickerController = [[UIImagePickerController alloc] init];        
        imagePickerController.delegate = self;
        imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
        imagePickerController.mediaTypes = [UIImagePickerController  availableMediaTypesForSourceType:imagePickerController.sourceType];
        imagePickerController.allowsEditing = YES;

        if ([self respondsToSelector:@selector(presentViewController:animated:completion:)]) {
            [self presentViewController:imagePickerController animated:YES completion:nil];
        } else {
            [self presentModalViewController:imagePickerController animated:YES];
        }        
        [imagePickerController release];
    }
}

-(IBAction)onClickChooseFromLibrary:(id)sender
{
    if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeSavedPhotosAlbum])
    {
        imagePickerController = [[UIImagePickerController alloc] init];
        imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
        imagePickerController.delegate = self;
        imagePickerController.allowsEditing = YES;
        imagePickerController.mediaTypes = [UIImagePickerController  availableMediaTypesForSourceType:imagePickerController.sourceType];
        popoverController= [[UIPopoverController alloc]
                        initWithContentViewController:imagePickerController];
        [popoverController presentPopoverFromRect:btnLibrary.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
    }
}

#pragma mark
#pragma mark - UIImagePickerDelegate
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{    
    if ([self respondsToSelector:@selector(dismissViewControllerAnimated:completion:)])   
    {
        [self dismissViewControllerAnimated:YES completion:nil];
    } else {
        [self dismissModalViewControllerAnimated:YES];
    }
    [popoverController dismissPopoverAnimated:YES];
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{    
    if ([self respondsToSelector:@selector(dismissViewControllerAnimated:completion:)]) 
    {
        [self dismissViewControllerAnimated:YES completion:nil];
    } else {
        [self dismissModalViewControllerAnimated:YES];
    }

    [popoverController dismissPopoverAnimated:YES];
    UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];
    [userImage setLocalImage:image];
}
D-eptdeveloper
  • 2,430
  • 1
  • 16
  • 30
  • 1
    Hey, thanks for your answer. I was actually using a PopOver when working with iOS 6, but since iOS 7 the camera is showing rotated 90 degrees when used in a PopOver. Even Apple recommend not using a popover anymore. You can see more info about this on this answer: http://stackoverflow.com/a/19030558/517688 – Jan Oct 03 '13 at 04:21
  • @Jan : if you could see that post and my answer both are same thing at there he said if you use camera as source type then present it on `presentModalViewController` but if you're picking image then open it in PopOver so my code is doing the same thing have a look and just try it once may be it solves your issue :) – D-eptdeveloper Oct 03 '13 at 04:27
  • @D-eptfeveloper : if you look closely at the question I linked to (I actually linked to an answer) he is telling to use `-presentViewController:animated:completion:`, and not `presentModalViewController`. – Jan Oct 03 '13 at 04:35
  • `presentModalViewController` is deprecated in iOS6 so i've put condition in my code that it uses according to the condition. – D-eptdeveloper Oct 03 '13 at 04:37
  • exactly, as it is deprecated, and I'm already using iOS7, it would be best to not even use it. And if I use your code, as iOS7 `respondsToSelector:@selector(presentViewController:animated:completion:)` I have again the problem that I'm describing in my question. – Jan Oct 03 '13 at 04:41
  • Just so you know, I did try using `presentModalViewController` even though is deprecated, and I'm still having the original problem. The presenting view controller is going away as well. – Jan Oct 03 '13 at 05:27
0

I had similar but not exact problem when I was trying to present UIImagePickerController from within UIContainerView.

Problem was that dismissing UIImagePickerController changed navigation in the very UIContainerView (resized to full-screen).

Solution was to present UIImagePickerController from within PARENT view controller of UIContainerView and now everything works perfectly.

vedrano
  • 2,961
  • 1
  • 28
  • 25
0

Just for notice, UIImagePickerController's delegate is "double delegate", it also delegate UINavigationControllerDelegate. See the code below.

@property(nullable,nonatomic,weak) id <UINavigationControllerDelegate, UIImagePickerControllerDelegate> delegate;

So, check if self also implement UINavigationControllerDelegate, and dismiss parent viewcontroller like below.

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    NSMutableArray *stack = [navigationController.viewControllers mutableCopy];
    if (stack.count >= 2) {
        [stack removeObjectAtIndex:(stack.count-2)];
    }
    navigationController.viewControllers = [stack copy];
    navigationController.delegate = nil;
}

Ok, I did and it cost me lots of time to find out. My situation may be not the common case. This is just for reference.

myron
  • 11
  • 3