I have a camera controller based on a UIImagePickerController:
#interface CameraController : UIImagePickerController
<UIImagePickerControllerDelegate>
// <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
{
}
#end
Init generates a warning that UINavigationControllerDelegate is not implemented (it is expected since I don't want my object to be that delegate):
- (id) init
{
if(!(self = [super init]))
return nil;
super.sourceType = UIImagePickerControllerSourceTypeCamera;
// Commenting delegat does not help
super.delegate = self;
return self;
}
Despite being a UIImagePickerControllerDelegate delegate, imagePickerController:didFinishPickingMediaWithInfo: is not called. I also verified the other two delegate methods are not being called either.
If I do claim adherence to UINavigationControllerDelegate, imagePickerController:didFinishPickingMediaWith is called but I crash on dismissModalViewControllerAnimated:
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
ASSERT_VALID(picker);
ASSERT_VALID(info);
// Commenting does not help
[picker autorelease];
UIImage* image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
ASSERT_VALID(image);
// Image processing commented out
// super.delegate = nil;
// picker.delegate = nil;
// [self dismissModalViewControllerAnimated:YES];
// [super dismissModalViewControllerAnimated:YES];
// [self performSelector:#selector(dismissModalViewControllerAnimated:) withObject:nil afterDelay:0.0f];
// [self dismissModalViewControllerAnimated:NO];
// [super dismissModalViewControllerAnimated:NO];
[self performSelector:#selector(dismissModalViewControllerAnimated:) withObject:nil afterDelay:0.5f];
}
I've looked at a number of posts on this CURSED view controller. The closest, UIImagePickerControllerDelegate not responding properly and iPhone - UIImagePickerControllerDelegate inheritance, did not help.
Any ideas what might be this time? Two questions immediately come to mind: (1) what does being a UINavigationControllerDelegate have to do with invoking my callback with the image, and (2) why can't this object clean itself up properly?
Thanks in advance,
The UIImagePickerController class is not supposed to be subclassed. The reference manual says:
This class is intended to be used
as-is and does not support
subclassing.
And there's no reason to. Just create a subclass of a UIViewController and implement the delegates.
I've successfully used it many times. I've always declared that my view controller implements UINavigationControllerDelegate but haven't implemented any of the methods of this protocol.
Related
I declared this in my header:
#import <UIKit/UIKit.h>
#interface NFNoteCamera : UIImagePickerController
#end
and receive 27 semantic issues such as
Property 'cameraCaptureMode' requires method 'cameraCaptureMode' to be defined - use #synthesize, #dynamic or provide a method implementation in this class implementation
including 'allowsImageEditing', 'allowsEditing' and other camera featured issues. If i had to guess it was something i haven't imported yet. Any Ideas?
as the doc says
Important The UIImagePickerController class supports portrait mode
only. This class is intended to be used as-is and does not support
subclassing. The view hierarchy for this class is private and must not
be modified, with one exception. In iOS 3.1 and later, you can assign
a custom view to the cameraOverlayView property and use that view to
present additional information or manage the interactions between the
camera interface and your code
why dont you just implement its delegate?
#interface NFNoteCamera : ParentClass <UIImagePickerControllerDelegate>
{
UIImagePickerController *yourPicker;
}
#end
#implementation NFNoteCamera
-(void)anyMethod{
yourPicker = [[UIImagePickerController alloc] init];
yourPicker.delegate = self;
[yourPicker setAllowsEditing:BOOL];
//or photo library(UIImagePickerControllerSourceTypePhotoLibrary)
yourPicker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:yourPicker animated:YES];
}
//delegate methods
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
UIImage *producedImage = [info objectForKey:UIImagePickerControllerOriginalImage];
}
#end
In my project I am using the UIIamgepickercontroller to select an image from the library and load it into a UIImageView. I am doing this for 2 images so I have two buttons for each image view, but I do not want to replicate the code for image picker twice and I'm not sure how to implement so that the method knows which image view to load the image into. I think I need to use button tags? but can't find the right method.
here's my code:
.h
`#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface LoadViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate> {
IBOutlet UIImageView *imageView;
IBOutlet UIImageView *imageView2;
}
- (IBAction)pick1;
- (IBAction)pick2;
- (void) getImage;
#end`
.m
#import "LoadViewController.h"
#implementation LoadViewController
UIImage *imageHandle;
- (IBAction)pick2 {
[self getImage];
imageView2.image = imageHandle;
}
- (IBAction)pick1{
[self getImage];
imageView.image = imageHandle;
}
- (void)getImage {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:picker animated:YES];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo {
imageHandle = image;
[picker.parentViewController dismissModalViewControllerAnimated:YES];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[picker.parentViewController dismissModalViewControllerAnimated:YES];
}
#end
Another problem I'v been having is that the methods to catch whether I have selected an image or cancelled the view do not seem to work although if I comment out the entire method (void)imagePickerControllerDidCancel then it will cancel?!?
I'm in the early stages of learning this stuff and any help would be very much appreciated!
Thanks
You can identify the button with a tag (you can set this in Interface Builder), which is an arbitrary integer. The problem is that you've rejected the chance to receive a reference to the sender (the button); instead of - (IBAction)pick1, say - (IBAction)pick1:(id)sender. Now you can check the sender's tag (cast the sender to a UIView* so the compiler understands what you're doing).
I am trying to open up a new view (UnprocessedPhotoViewController) immediately after the delegate function for my UIImagePickerController returns a "didFinishPickingImage".
Unfortunately, it appears that I can either open the UIImagePickerController modal view, or switch to the UnprocessedPhotoViewController as a modal, but not both sequentially.
In the code below, a button press activates the pickPhoto IBAction. This code activates the UIImagePickerController successfully. After the user selects an image, the didFinishPickingImage delegate function is called, which stores the image to a variable, attempts to close the UIImagePickerController modal and open the UnprocessedPhotoViewController in a new modal.
Note: If I comment out the ImagePicker and run "showPhoto" directly, the UnprocessedPhotoViewController shows successfully. Also, if I make a new button to launch either view it works successfully, but I am unable to launch the views sequentially. I would expect that after a user selected the image, the new view would be launched which would allow the user to process the image.
What is the correct way to guarantee that the ImagePicker modal closes and then to open the UnprocessedPhotoViewController?
Thanks!!!
Code:
- (IBAction)pickPhoto:(id)sender{
//TODO: To be replaced with the gallery control launching code
// Load Image Selection Code
self.imgPicker = [[UIImagePickerController alloc] init];
self.imgPicker.delegate = self;
self.imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:self.imgPicker animated:YES];
}
// Dummy function assumes you either picked (or took a picture =D) of Angie and moves you right to the unprocessed viewing screen.
- (void) showPhoto{
// Start new view controller
[self dismissModalViewControllerAnimated:YES];
UnprocessedPhotoViewController *upViewController = [[UnprocessedPhotoViewController alloc] initWithNibName:#"UnprocessedPhotoViewController" bundle:nil];
upViewController.imageView.image = selectedImage;
upViewController.delegate = self;
upViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:[upViewController animated:YES]];
[upViewController release];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img {
selectedImage = img;
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
[self dismissModalViewControllerAnimated:YES];
[self showPhoto];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
}
Implement viewDidAppear in your root view controller and based on member data decide to call showPhoto or not. The following example simply re-presents the UIImagePicker but any new modal view will work. viewDidAppear is called any time your root view controller’s view appears so you have to make sure the context is known when it is called. But it is the deterministic way to know that the modal view controller is gone.
- (IBAction) showPicker: (id) sender
{
UIImagePickerController* picker = [[[UIImagePickerController alloc] init] autorelease];
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
picker.delegate = self;
picker.allowsEditing = YES;
[self presentModalViewController:picker animated:YES];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
imageChosen = YES;
[self dismissModalViewControllerAnimated:YES];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
imageChosen = NO;
[self dismissModalViewControllerAnimated:YES];
}
- (void) viewDidAppear: (BOOL) animated
{
if ( imageChosen )
{
[self showPicker: self];
}
}
Another way to do this is to wrap the built-in dismissal animation with your own animation, and then catch the animationDidStop "event." This creates a composite animation, so when the built-in animation is done, your (empty) wrapper animation finishes you and alerts you that you're done.
This is slightly cleaner than the other answer here, IMO, as you don't need to keep a state variable or override viewDidAppear: (in my app, the view controller presenting the picker is quite a few objects removed from the utility code that handles picker management, and that would mean any view controller using my shared utility would have to override viewDidAppear:, or else fail to work):
-(void)dismissalAnimationDone:(NSString*)animationID
finished:(BOOL)finished context:(void*)context
{
UIImage* image = (UIImage*) context;
// present controllers as you please
}
-(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
{
[UIView beginAnimations:#"dismissal wrapper" context:image];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(dismissalAnimationDone:finished:context:)];
[self.delegate dismissModalViewControllerAnimated:YES];
[UIView commitAnimations];
}
UIImagePickerController is easy to use, but i'm all of a sudden finding it exasperating when I didn't find it so before. What's happening is that sometimes the imagePickerController:didFinishPickingImage:editingInfo delegate method does not seem to work -- the image will not show in the UIImageView even after the assignment was made. Sometimes it will, sometimes not, and furthermore, every single bit of example code i've tried (from the web, from the "Beginning iPhone 3 Development" book, etc.) exhibits the same problem. I'm at a loss as to why, and the problem happens on both my iPhone 3G as well as my 3GS, so I doubt that it's a hardware issue. These devices are running OS 3.1.2. The view controller is loaded from a xib file that contains one button and the UIImageView. I'd really like someone to tell me what stupid thing i'm obviously doing wrong :-)
Here is the code -- i've tried to make the smallest app I could that exhibits the problem:
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface imagepickerViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate>
{
IBOutlet UIButton *button;
IBOutlet UIImageView *imageView;
}
#property (nonatomic, retain) UIImageView *imageView;
- (IBAction)takepic;
- (void)usePic:(UIImage *)pic;
#end
#import "imagepickerViewController.h"
#implementation imagepickerViewController
#synthesize imageView;
- (IBAction)takepic
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.delegate = self;
[self presentModalViewController:picker animated:YES];
[picker release];
}
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)info
{
[self usePic:image];
[picker dismissModalViewControllerAnimated:YES];
// after this method returns, the UIImageView should show the image -- yet very often it does not ...
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[picker dismissModalViewControllerAnimated:YES];
}
- (void)usePic:(UIImage *)picture
{
imageView.image = picture;
}
#end
I came accross this issue recently too. My solution was to dismiss the modal UIImagePickerController view prior to using the image.
By dismissing the image picker, the previous view controller's view is reloaded, and the UIImageView which was to be the recipient of the chosen image is reloaded and no longer nil.
i.e. I changed from this:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
// Wrong! imageView has been released by the UIViewController after a low memory warning and is now nil.
[imageView setImage:image];
[self dismissModalViewControllerAnimated:YES];
}
to this:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
// Dismis the image picker first which causes the UIViewController to reload it's view (and therefore also imageView)
[self dismissModalViewControllerAnimated:YES];
[imageView setImage:image];
}
My guess: make sure you're handling didReceiveMemoryWarning correctly. Put a breakpoint or a debug printout or something to see if it's being hit, and then check what's happening next.
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
NSLog(#"Got a memory warning");
}
The default handling is for UIViewControllers that are not visible (and your app's main view controller is not visible while the picker is in front of it!) to discard their views.
I have had the same problem. When the imagePicker is opened there is a memory warning and the ViewController is discarted. So you lose anything in your ViewController. For example if you have any UITextField you will also lose its content. So you need to store the state of your ViewController somewhere else when the method didReceiveMemoryWarning is called. You can store values in the NSUserDefaults, in files, in your AppDelegate,...
Saving an image in a file is a big time consumption task. So my solution has been to save the image in the AppDelegate, in memory. I've created an UIImage *image variable inside the delegate. Then when the imagePicker finishes I store the image in that field:
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *editedImage = [info objectForKey:UIImagePickerControllerEditedImage];
imageView.image = editedImage; // it works if no memory warning is received
YourAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
delegate.image = editedImage;
}
Then if the ViewController has been discarted it's needed to read the stored image from the AppDelegate in the viewDidLoad method.
- (void)viewDidLoad {
[super viewDidLoad];
// if you have used NSUserDefalts to store the state of your UITextFields
// when the didReceiveMemoryWarning was called
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *name = [defaults objectForKey:#"name"];
if (name != nil) {
textFieldName.text = name;
}
// show the saved image
YourAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
UIImage *image = delegate.image;
if (image != nil) {
imageView.image = image;
}
}
I've tried all these techniques and no joy. The image view does change shape to match the photo but the only thing that display's is the background. and if i attempt to take a photo the second time it works...
This doesn't make any sense whatsoever...could it be a problem with the XIB ??
I followed a great tutorial (http://iphone.zcentric.com/2008/08/28/using-a-uiimagepickercontroller/) on using a UIImagePickerController to get images from the Photo Album or Camera on the iPhone. The problem is, the tutorial is a bit dated and documentation cites a method used by the delegate as being depreciated since 3.0. The problem is, the documentation failed to provide clues as to what to use in place? The deprecated method is:
– imagePickerController:didFinishPickingImage:editingInfo:
The above method is used as follows:
- (void) imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)img editingInfo:(NSDictionary*)editInfo
{
image.image = img;
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
}
QUESTION: What is currently used in place of the deprecated method?
Here's how to use the new image picker API in a nutshell.
First, you need a class declared like this since it's setting itself as the image picker delegate:
#interface MyClass : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate> {
UIImagePickerController* imagePicker;
}
#property(nonatomic,retain) UIImagePickerController* imagePicker;
- (IBAction) takePicture:(id)sender;
#end
The method that brings up the image picker would go something like this. It's declared here as an IBAction so you can directly wire it to a control (like a button) in Interface Builder. It also checks so that if you're on an iPhone it brings up the camera interface but on an iPod Touch it brings up the gallery picker:
#import <MobileCoreServices/UTCoreTypes.h>
...
#synthesize imagePicker = _imagePicker;
...
- (void) takePicture:(id)sender
{
if (!_imagePicker) {
self.imagePicker = [[UIImagePickerController alloc] init];
self.imagePicker.delegate = self;
}
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
NSArray* mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];
self.imagePicker.mediaTypes = mediaTypes;
} else {
self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
self.imagePicker.allowsImageEditing = YES;
}
[self presentModalViewController:self.imagePicker animated:YES];
}
Then you need these two methods:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
// MediaType can be kUTTypeImage or kUTTypeMovie. If it's a movie then you
// can get the URL to the actual file itself. This example only looks for images.
//
NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
// NSString* videoUrl = [info objectForKey:UIImagePickerControllerMediaURL];
// Try getting the edited image first. If it doesn't exist then you get the
// original image.
//
if (CFStringCompare((CFStringRef) mediaType, kUTTypeImage, 0) == kCFCompareEqualTo) {
UIImage* picture = [info objectForKey:UIImagePickerControllerEditedImage];
if (!picture)
picture = [info objectForKey:UIImagePickerControllerOriginalImage];
// **You can now do something with the picture.
}
self.imagePicker = nil;
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
self.imagePicker = nil;
}
Quoting the Apple documentation:
imagePickerController:didFinishPickingImage:editingInfo:
Tells the delegate that the user picked an image. This method is optional. (Deprecated in iPhone OS 3.0. Use imagePickerController:didFinishPickingMediaWithInfo: instead.)