Proper use of UIImagePickerController for both taking pictures with camera or selecting them from the iphone library - iphone

What I want to do is to always use the same instance of UIImagePickerController in my whole app, since i don't want to alloc and destroy my picker every time the user takes a picture. The app uses a picker and an UIImageView named pictureA to show the picture choossen from the iPhone album or taken with the camera.
At start I allock my picker view controller like this:
imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.delegate = self;
[self addSubview:imagePickerController.view];
When I take picture from the picker and place it in my UIImageView:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
// newImage is a UIImage do not try to use a UIImageView
UIImage *newImage = [info objectForKey:#"UIImagePickerControllerEditedImage"];
[pictureA removeFromSuperview];
CGRect myImageRect = CGRectMake(30.0f, 38.0f, 125.0f, 125.0f);
pictureA = [[UIImageView alloc] initWithFrame:myImageRect];
pictureA.contentMode= UIViewContentModeScaleAspectFit;
[pictureA setImage:newImage];
pictureA.opaque = YES;
[self addSubview:pictureA];
[newImage release];
[picker dismissModalViewControllerAnimated:YES];
[picker.view setHidden:YES];
}
When chooses a picture from the iphone's library:
- (void) chooseImageFromLibrary {
[imagePickerController.view setHidden:NO];
imagePickerController.allowsEditing = YES;
[imagePickerController viewWillAppear:YES];
[imagePickerController viewDidAppear:YES];
}
Cancel:
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
[picker.view setHidden:YES];
}
- (void) takePicture {
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
[(MainScene*)[melonGame actualScene] setCameraDissabled:YES];
return;
}
[imagePickerController.view setHidden:NO];
imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePickerController.allowsEditing = YES;
[imagePickerController takePicture];
[imagePickerController viewWillAppear:YES];
[imagePickerController viewDidAppear:YES];
}
The app will work properly when i take the first picture, but when i try to take another picture or choose another picture from my library it looks exactly as the last time i selected a picture ( with the picture in all the screen and an inactive menu to choose and cancel at the bottom). My app only works correctly if i remove the controller from my view and alloc it every time the user takes a picture. Is there any way to "clean" or "restart" the picker without releasing it and removing it from my view ?
I'm also not sure if i can instance once the UIImageView ( pictureA) where I store the image taken by the imagePickerController and modify it every time the user takes a picture or chooses one from the album, i suspect that it's incorrect to destroy it and realloc it every time the user takes a picture. Any suggestions ?, any thing i'm doing wrong regarding memory management or the use of the UIImagePickerController and the UIImageView ?
thanks !

I don't think UIImagePickerControllers are meant to be re-used. Either way, they use a TON of memory (especially the camera), so you don't want to keep them around any longer than you have to. So yes, you should release the image picker when you're done with it, and create a new one when you want to add another image.
You should probably be presenting your imagepicker modally:
[self presentModalViewController:imagePickerController animated:YES];
You don't need to release your pictureA image view every time you want to change the image. Just change the image property.
pictureA.image = newImage;
If you want to instantiate the image view the first time you use it, do something like
if (!pictureA) {
pictureA = [[UIImageView alloc] initWithFrame:aFrame];
}
pictureA.image = ...
Keep in mind that a call to alloc needs a matching call to either release or autorelease. When you allocated "pictureA" above, its retain count became 1. calling "[self addSubview:pictureA];" increased its retain count to 2. When you called "[pictureA removeFromSuperview];" next time around, the retain count was decreased to 1, and you created a new imageview. So every time imagePickerController:didFinishPickingMediaWithInfo: is called, you will leak memory. Instead, do
[pictureA removeFromSuperview];
[pictureA release];
when you remove it from superview. Or, better yet, make picture a property of the class:
#property (nonatomic, retain) UIImageView *pictureA;
which will release the old imageView when you assign a new one. Just make sure to release when you assign it :)
self.pictureA = [[[UIImageView alloc] init] autorelease];
or
UIImageView *imageView = [[UIImageView alloc] init];
self.pictureA = imageView;
[imageView release];
I would personally stick with the autorelease style because you'll always be able to tell at a glance if you're allocing/deallocing properly.
Also, you can always double-check your memory management using Product>Analyze in Xcode 4.

Related

Received memory warning. with ipad camera

When i open Camera in my app it works fine, but when i navigate in my app and comes back to camera view and again try to open my camera in iPad, app crashes and gives me "Received memory warning". app working fine in iPhone and this issues is only coming in iPad.
My project was without ARC so i converted my project into ARC in the hope to get good results but still my app crashes on camera after little navigation.
can anybody tell me how to decrease memory space with iPad camera so that my apps stop receiving memory warning.
this is my code for camera
if ([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera])
{
imagePicker=[[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.sourceType =UIImagePickerControllerSourceTypeCamera;
imagePicker.allowsEditing = NO;
//imagePicker.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:imagePicker animated:YES completion:nil];
}
This is where I get my Image
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[Array removeAllObjects];
[picker dismissViewControllerAnimated:YES completion:nil];
image = [info objectForKey:UIImagePickerControllerOriginalImage];
[array addObject:image];
image=nil;
}
and i have also try to use popOverview for camera but it also didn't work.
In my viewController where I'm calling UIImagePickerController I have used 5 animations, before i was calling animation in viewWillAppear, and app was crashing so i changed Animation calling to ViewDidLoad and camera starting working but only until I navigate to my last view and comes back to open camera again.
I am getting same problem so i do like this.
Set UIImagePickerController as static like this.
static UIImagePickerController *imagePicker;
When you get image in this deleget.
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
#autoreleasepool {// to release memory
// Probelm is you image size.
// When you get this image it is vary large.
// And i hope you are creating multiple copy's of this image.
// when you get image in
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
// In last set image as nil
image = nil;
}
}
Hope this will solve you problem.. :-)
Try to run your app without animation and then try, if it works then you need to improve your animations memory allocation, as animation needs a lot of memory.
Please try below code.try UIImagePickerController with in popover
if([UIImagePickerContrller isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
UIImagePickerController *controller = [[UIImagePickerController alloc] init];
controller.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
controller.allowsEditing = YES;
controller.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
controller.delegate = self;
UIPopoverController *popController = [[UIPopoverController alloc] initWithContentViewController:controller];
popController.popoverContentSize = CGSizeMake(350.0f, 500);
[popController presentPopoverFromRect: self.button.frame inView:self.button.superview
permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES]
}

Best way to use imagepickercontroller in iphone?

I am using UIImagePickerController to select the image from the PhotoLibrary in my application. I have used two different approaches for this. At first I have used a class variouble UIImagePicker with below code.
imagepicker = [[UIImagePickerController alloc]init];
imagepicker.delegate = self;
imagepicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagepicker.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentModalViewController:self.imagepicker animated:YES];
Above code is working fine.But when I clicked on the button it is taking some time to react with the animation in this case.Then I used the autorelease pool approach with this method
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
if([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypePhotoLibrary])
{
UIImagePickerController *picker= [[[UIImagePickerController alloc]init]autorelease];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
picker.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentModalViewController:picker animated:YES];
}
[pool release];
Also works charm. Both of them showing no leak in the analyser.Can anybody point me the right approach.
Well, no much to say here... Both approaches work, both approaches are correct, use whichever you prefer.
One minor point: if you are regularly presenting the image picker, you better use the first method, and assign it to an instance variable (it isn't called a "class variable"!) only for the first time, and don't release it until - dealloc - this way, you save the continuous allocation-deallocation of the image picker every single time the user chooses an image.

Access/Reference imageView.image to replace it later

Alright, this has been driving me insane for the last few days. I hope this is an easy fix. I am trying to access my UIImageView.image so I can replace it later.
With only the needed code here it is:
I first create an imageView for each time a user clicks on a photo in their Library.
// .h
#property (strong,nonatomic) UIImage *doneImage;
#property (strong,nonatomic) UIImageView *editImage;
// .m
#synthesize doneImage;
#synthesize editImage;
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *originalImage = [info objectForKey:UIImagePickerControllerOriginalImage];
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(xCoordinate, yCoordinate, widthOfImage, heightOfImage)];
imgView.image = originalImage;
imgView.userInteractionEnabled = YES;
[self.mainView addSubview:imgView];
// I add gestures
longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(handleLongPress:)];
longPress.minimumPressDuration = 1;
longPress.numberOfTouchesRequired = 1;
[imgView addGestureRecognizer:longPress];
}
When someone clicks holds down on one of those images this pops up
- (void)handleLongPress:(UILongPressGestureRecognizer *)recognizer {
editImage = (UIImageView*)recognizer.view; // I declare what editImage is and now have access to what imageView is being interacted with.
doneImage = editImage.image; // I then get the image of that for later use.
if(UIGestureRecognizerStateBegan == recognizer.state) {
popoverEditor = [[UIPopoverController alloc] initWithContentViewController:[self.storyboard instantiateViewControllerWithIdentifier:#"popupEditor"]];
[popoverEditor presentPopoverFromRect:editImage.bounds inView:editImage permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
This pops up a menu with 4 buttons. I then have an IBAction that tries to fire up the editing part.
- (IBAction)effectsEditorButton:(id)sender {
// editImage is my imageView
if (editImage == nil) {
NSLog(#"imageView was nil wtf");
} else {
[self performSelector:#selector(editImageWithEffects:)];
}
}
My image view is ALWAYS nil. I need to get a reference to that somehow. I've tried tags but I can't seem to get them to hold their value once I get to this point.
Any help would be very much Appreciated. Thanks!
Are you leaving out code? Based on what you have here, editImage will always be null because it isn't declared anywhere (perhaps something in Interface Builder that we can't see?).
You need a way to link back into your view controller from your popover. Popular ways to do this are to use a completion block when returning from your popover controller, or setting your "main" VC as a weak property on the popover.

Update UILabel from applicationDidBecomeActive?

I want to update UILabel by clicking a reload button. Additionally, I want to update the label in background, because it is fetching the new data via XML from my website. Of course it would be nice to auto-update the label when the application is opened. And there is my problem:
I was able to make it work well when user were clicking the button manually. But I don't understand how to do the same by calling my method via "applicationDidBecomeActive". I tried to do it the same way, but it obviously doesn't work because my label is returned nil.
I suppose there is a problem of my understanding and the solution should be quite easy. Thanks for your input! Note: I am a beginner with Objective-C and have sometimes problems with "easy" things. ;-)
Below is a summary of the important code parts:
AppDelegate
- (void)applicationDidBecomeActive:(UIApplication *)application {
[[MyViewController alloc] reloadButtonAction];
}
MyViewController
#synthesize label
- (void)reloadButtonAction {
[self performSelectorInBackground:#selector(updateData) withObject:nil];
}
- (void)updateData {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Parse the XML File and save the data via NSUserDefaults
[[XMLParser alloc] parseXMLFileAtURL];
// Update the labels
[self performSelectorOnMainThread:#selector(updateLabels) withObject:nil waitUntilDone:NO];
[pool release];
}
- (void)updateLabels {
NSUserDefaults *variable = [NSUserDefaults standardUserDefaults];
myLabel.text = [variable stringForKey:#"myLabelText"];
// myLabel is nil when calling all of this via AppDelegate
// so no changes to the myLabel are done in that case
// but: it works perfectly when called via button selector (see below)
NSLog(#"%#",myLabel.text);
}
-(void)viewDidLoad {
// Reload button in the center
UIButton *reloadButton = [UIButton buttonWithType:UIBarButtonSystemItemRefresh];
reloadButton.frame = CGRectMake(145,75,30,30);
[reloadButton setTitle:#"" forState:UIControlStateNormal];
[reloadButton addTarget:self action:#selector(reloadButtonAction) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:reloadButton];
}
First:
[[MyViewController alloc] reloadButtonAction];
Doesn't make sense. You allocate memory, without initializing an object. And then you want to call a method on it. Doesn't work
Use an instance for it:
[myViewControllerInstance reloadButtonAction];
In your app delegate you should have an reference to your rootcontroller instance if that is the object contains the reload method, use that instance.
Note:
Alloc only reserves space in the memory for an object which size the size of MyViewController instance. An init method will fill it.

iPhone UIImageView with Camera or Camera Roll Picker Memory Warning Level 2

I'm soooooo close to finally finishing my first app to put in the store. Everything works just fine and memory leaks are almost totally nonexistent....except when I'm using the Camera or Selecting an Image from the Camera roll.
If the user chooses the camera vs. the roll....the camera works fine...takes a picture and then when they select "Use" it crashes. Same thing for the camera roll. I'm a noob so if I messed something up it wouldn't surprise me. Any help/suggestions greatly appreciated...here's the code:
-(IBAction) getPhoto:(id) sender {
UIImagePickerController * picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
if((UIButton *) sender == choosePhoto) {
picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
} else {
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
}
[self presentModalViewController:picker animated:YES];
//[picker release];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[picker dismissModalViewControllerAnimated:YES];
theimageView.image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
[picker release];
}
Your problem might be, since you use the original image, since its something like 1400x750 (not sure about the exact dimensions), you are probably running out of memory when you are setting it as the image of the imageview to be displayed...You should probably resize your image to 320x480 or 480x320 to display it in the image view, that will probably fix your problem.
The only issue that jumps out at me is that UIImagePickerControllerOriginalImage is an NSString constant, so you don't want to put it in quotes:
theimageView.image = [info objectForKey:UIImagePickerControllerOriginalImage];
But even if that line were to fail, it would only set theimageView.image to nil which probably shouldn't cause a crash. You should see at least some more info about the crash in the Xcode Console, which will help. Also, check out the tips in this SO answer.
Change
[picker dismissModalViewControllerAnimated:YES];
to
[self dismissModalViewControllerAnimated:YES];
That should work