user748176
user748176

Reputation:

Can't get UIImagePickerController to work?

-(void) openPhotoLib:(id)sender {
    [self dismissModalViewControllerAnimated:YES];
    UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
    [imagePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
    [imagePicker setDelegate:self];
    [self presentModalViewController:imagePicker animated:YES];
    NSLog(@"openPhotoLib called");
}

Nothing happens except for the NSLog, even though my view controller is a subclass of UINavigationController and UIImagePickerDelegate. Does anyone have any insight or experience with UIImagePickerController?

I should note that I'm primarily using an iPhone for testing.

SOLUTION: Make a new class that subclasses ONLY UINavigationBarDelegate and UIImagePickerDelegate. In that classes's viewDidAppear, put the code to modally present the imagePicker. Create an instance of this class inside the method (inside another class, import the .h file and all) and the modally present that class.

^ I take it back. The modal animations was the real problem. Trying to use another class instance for this messes up the method implementations of UIImagePicker.

Upvotes: 0

Views: 267

Answers (2)

Vaibhav Garg
Vaibhav Garg

Reputation: 3716

The problem is due to dismissModalViewControllerAnimated and presentModalViewController being called one after the other.

The dismiss action takes some time as it has to animate the view being dismissed. During the animation, it is still the top Modal View. So, you cant present another model view during that time. If you try then the call fails and does nothing.

To fix, use [self dismissModalViewControllerAnimated:NO]; i.e no animation.

If you still want animation then follow one of these solutions:

Problem opening new ViewController after UIImagePickerController

Correct way of showing consecutive modalViews

Upvotes: 1

sergio
sergio

Reputation: 69027

EDIT:

If using storyboards, you should define prepareFroSegue in your delegate:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"AddPlayer"])
{
    PlayerDetailsViewController 
      *playerDetailsViewController = 
        (PlayerDetailsViewController *) segue.destinationViewController;

    playerDetailsViewController.delegate = self;
}
}

(source)

Am I not sure, but I think that the call:

[self dismissModalViewControllerAnimated:YES];

might interfere with the following call

[self presentModalViewController:imagePicker animated:YES];

since both are done within the same run loop.

I would suggest doing like this:

  1. define a method to encapsulate the call to presentModal...

    - (void)presentPicker:(...)picker {
        [self presentModalViewController:imagePicker animated:YES];
    }
    
  2. replace the original call to presentModal... with:

     [self performSelector:@selector(presentPicker:) withObject:picker afterDelay:0.0];
    

Explanation: by using performSelector the way I suggest, we are simply enqueuing the call to presentPicker in the run loop (without any delay actually, since we specify 0.0 as a delay value). In this way, we give UIKit a chance to dismiss the modal view and do all necessary clean up before we try and present the next modal view.

The reason to define presentPicker as a method is that performSelector only allows to specify one single argument (instead of the two that presentModal... requires).

Hope this helps.

Upvotes: 0

Related Questions