I have a modal which displays a UIImagePicker and allows the user to take a photo which then gets put into a UIImageView.
Every now and then I get a memory warning 'Received Memory Warning' and the UIImageView does not get assigned. The App is fairly simple and it's not using a lot of memory, and it seems that a lot of the time this has to do with the ImagePicker as a separate process. This only happens when using the camera, and it happens about one in five times.
There's a lot of talk about this online, and most of the answers say to 'handle the warning appropriately'; but I"m not sure what that means - I just want the taken photo to show up in the ImageView! It seems to happen before I can do anything about it in the UIImagePicker delegate.
What can I do to mitigate this?
Here's the didFinishPickingImage Delegate:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)selectedImage editingInfo:(NSDictionary *)editingInfo {
//set background for image select button, put image reference somewhere to copy image to documents folder and insert into modular's sentence object.
//ImagePicker.jpg needs it's border set to 1px black.
NSLog(#"imagePickerController: selectedimage: %#", selectedImage);
imageViewBehindPhotoBigButton.clipsToBounds = YES;
[imageViewBehindPhotoBigButton.layer setBorderColor: [[UIColor blackColor] CGColor]];
[imageViewBehindPhotoBigButton.layer setBorderWidth: 1.0];
[imageViewBehindPhotoBigButton setBackgroundColor:[UIColor whiteColor]];
[imageViewBehindPhotoBigButton setContentMode: UIViewContentModeScaleAspectFill];
imageViewBehindPhotoBigButton.image = selectedImage;
imageViewBehindPhotoBigButton.hidden = NO;
[choosePhotoBigButton setBackgroundImage:nil forState:UIControlStateNormal];
choosePhotoBarImage.hidden = NO;
choosePhotoText.hidden = NO;
addButton.enabled = YES;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
//because iPad uses a pop up - we don't want to dismiss modals here!
[imagePopupController dismissPopoverAnimated:YES];
}else{
[self dismissModalViewControllerAnimated:YES];
}
}
The answer was to implement threading when scaling / handling the image from the UIImagePickerController. There's a really good discussion that I used here.
Related
I have seen this question being asked many times before but I can't seem to get an answer that helps me. So here is my situation :
I have a user press a button that asks them if they want to take a picture or choose one from their album. When testing on my actual phone the choosing from album mode works, but the picture from camera goes all weird.
What happens : User is shown camera view -> user takes picture -> CRASH
The crash is not one in the console tho... I get a window on top of my xCode window saying :
App stopped unexpectedly due to Memory Pressure.
So I read that I need to resize the image I am getting from the camera before I display a small thumbnail for the user... I am doing that but to no avail... this has now become a consistent issue.
Here is my code :
(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[self dismissViewControllerAnimated:YES completion:nil];
//UIImage *img = [info objectForKey:UIImagePickerControllerOriginalImage];
CGRect rect = CGRectMake(0,0,320,480);
UIGraphicsBeginImageContext(rect.size);
//[img drawInRect:rect];
UIImage *picture1 = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[_photoTaken setImage:picture1];
[self updateAppropriateCharacterCount];
[_userInputTextField becomeFirstResponder];
}
Let me explain what the variables are :
_photoTaken is a pointer to a UIImageView where I want to display the thumbnail. It is much smaller than 320 x 480 though.
Now I also have this method :
(void) takePhotoButtonPressed {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = NO;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentViewController:picker animated:YES completion:nil];
}
Finally before I did all this funny resize stuff I was setting the "img" variable to another pointer called "image" that was defined in my local implantation. I was using this to check (later in the code) if an image existed.
Any help would be appreciated, or some guidance.
Thank you much
EDIT
I also noticed that if I run my app for some time before going right to taking a picture it crashes before even showing the camera - I press take a photo and bam dead....
I have a project designed to be more memory efficient for taking pictures. The files will be larger than thumbnail, but it usually runs much lighter than UIImagePicker, and the final picture files are significantly smaller.
You can find it here
i'm trying to create a photo viewer like the Apple Photos app in iOS.
The layout is ok, but it receives memory warning and then crashes. Why? This happens even i load 7/8 images from the app documents folder. Have i to manage the memory with specific system? I use ARC with iOS 5.
EDIT :
The code :
for (int i=0; i<[dataSource count]; i++) {
UIButton *button=[UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:[dataSource objectAtIndex:i] forState:UIControlStateNormal];
[[button titleLabel] setText:[NSString stringWithFormat:#"%i",i+1]];
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[[button layer] setBorderWidth:1];
[[button layer] setBorderColor:[UIColor darkGrayColor].CGColor];
if (i==0) {
[button setFrame:CGRectMake(x, y, width, height)];
} else {
if (i%5==0) {
nRow++;
x=18;
[button setFrame:CGRectMake(x, (y*nRow), width, height)];
} else {
[button setFrame:CGRectMake(x+space+width, (y*nRow), width, height)];
x=button.frame.origin.x;
}
}
[[self view] addSubview:button];
}
The main part of this code is the first 6 lines, after is all x and y.
dataSource is an NSArray declared as property (nonatomic, strong). It contains UIImage objects.
You should be lazily loading your images in conjunction with reusing your buttons to account for the possibility of a large number of images.
To implement:
Keep the paths to the image files in your data array instead of the UIImage objects. Get the image from the path using imageWithContentsOfFile: when you need it.
Load the first z buttons into the scroll view where z is the number that appear on the screen at a time plus one row's worth.
Set the UIViewController that we are currently in as the scrollview's delegate, and respond to changes in offset by repositioning buttons and setting appropriate images and targets.
Also, if 7/8 images is crashing your app, it sounds like you're dealing with some pretty large image files. Try to provide thumbnail-sized versions of the content within the documents directory(whatever the size of your buttons are EXACTLY), or if images are dynamic, see this post for a how-to.
If you are probably using ImageNamed, this article helped me alot:
http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/
Mainly
DO NOT USE [UIImage imageNamed] for any significant amount of images. It is EVIL. It WILL bring down your application and/or Springboard, even when your application is putting along using just barely a nibble of memory on its own.
and
it is better to implement your own cache
and here's the proposed cached image example:
- (UIImage*)thumbnailImage:(NSString*)fileName
{
UIImage *thumbnail = [thumbnailCache objectForKey:fileName];
if (nil == thumbnail)
{
NSString *thumbnailFile = [NSString stringWithFormat:#"%#/thumbnails/%#.jpg", [[NSBundle mainBundle] resourcePath], fileName];
thumbnail = [UIImage imageWithContentsOfFile:thumbnailFile];
[thumbnailCache setObject:thumbnail forKey:fileName];
}
return thumbnail;
}
I am trying to take a picture with my app and then show it in a UIImageView that is predefined in my .xib. I have a IBOutlet UIImageView *_foto that is linked to the UIImageView in the .xib
When I do the following the picture doesnt show in the UIImageView after taking a picture:
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo
{
_foto.image = image;
//Also tried set image, and resizing the image first
[self dismissModalViewControllerAnimated:YES];
}
Now, when I add code to create a new image view with the image returned from my picker, and add that as a subView to my view like this, something strange happens:
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo
{
UIImageView *iv = [ [UIImageView alloc] initWithImage:image];
[self.view addSubview:iv];
[iv release];
_foto.image = image;
[self dismissModalViewControllerAnimated:YES];
}
Now the image shows in both the newly created image view in the left top corner of my view,as expected, but also in my _foto UIImageView. This has me seriously confused, and I have no idea what is going on, all i know is that it is not the behavior i expected. Does anyone have any clue, and hopefully a proper solution for this problem?
Artur Ozierański's answer is partially correct.
If you're using viewDidLayoutSubviews() to configure your layout, this gets called when the picker disappears, so if you're setting the default image in viewDidLayoutSubviews(), you'll reset back to the default image.
Configure the default image in viewDidLoad.
UIImagePickerController grab a lot of device memory while picking an image. During - (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo I've noticed many times memory warnings level 1 and 2. It may cause force unload and reload your view, launch viewDidLoad method of your view controller again. If your _foto object is an IBOutlet it will be removed from memory and load again with start values of all properties (image too). Also if you set image to nil in viewDidLoad it may be a reason.
Put some NSLog into viewDidLoad to check out if it is relaunched. Also you may try to put captured image into library - if image exists in library the problem probably is in view unloading.
I need to let the user select a photo from the Photo Library and be able to size and crop their image while using an Overlay image. Using UIImagePickerControllerSourceTypeCamera with cameraOverlayView is fine, but UIImagePickerControllerSourceTypeSavedPhotosAlbum does not support that property.
Strangely enough, when I add the overlay view as a subView with alpha set at half, the overlay appears on the Photo selection screen, but this wont fly with Apple's approval process.
-(void)choosePhotoDialog:(id)sender
{
UIBarButtonItem * barThing = (UIBarButtonItem*)sender;
OverlayView * overlay = [[OverlayView alloc] initWithFrame: CGRectMake(0, 0, SCREEN_WIDTH_IPHONE, SCREEN_HEIGTH_IPHONE)
andPhotoOverlay: [dict objectForKey:#"imageUrl"]];
[overlay setUserInteractionEnabled: NO];
UIImagePickerController * picker = [[UIImagePickerController alloc] init];
switch (barThing.tag)
{
case 0: [picker setSourceType: UIImagePickerControllerSourceTypeCamera];
[picker setShowsCameraControls: YES];
[picker setCameraOverlayView: overlay];
break;
case 1: [picker setSourceType: UIImagePickerControllerSourceTypeSavedPhotosAlbum];
[picker.view addSubview: overlay];
[overlay setAlpha: 0.5f];
break;
}
[picker setDelegate: self];
[picker setAllowsEditing: YES];
[picker setNavigationBarHidden: YES];
[picker setWantsFullScreenLayout: YES];
[self presentModalViewController:picker animated:YES];
[picker release];
}
Question
What is the correct way to allow a user to select a photo from the PhotoLibrary with an Overlay using UIImagePickerControllerSourceTypeSavedPhotosAlbum?
Resolved
Basically, I needed to write 3 separate classes and combine them to create my own custom photo editing view, which also saves pinch / zoom / rotate edits.
I ended up writing several classes:
An OverlayView class which is a UIView and simply retrieves the .png image with transparency and is the bottom-most layer.
An InteractiveWallpaper class which is a UIImageView and handles all of the touch events, including the transformation events.
And finally, an EditingView class which is a UIViewController. This adds the 2 views previously mentioned as well as saves the photo that the user edited.
This also allowed me to customize the behavior of the view. When the user touches the imported photo, the top-most photo decreases it's alpha value, allowing the user to still see the overlay while the imported photo is more visible.
I am working on an application for iPad, it is working fine until i reached this point:
The app shows the popover for the photo library, but when I choose the photo, the popover doesn't hide, and I also want it to view the selected image in a UIImageView, however i do not know how.
I am sure there is something wrong in the didFinishpickingMediaWithInfo function. here is the function's code:
-(void) imagePickerController:(UIImagePickerController *)picker didFinishpickingMediaWithInfo:(NSDictionary *)info{
//bgImage is a UIImageView
bgImage = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
// Dismiss UIImagePickerController and release it [picker dismissModalViewControllerAnimated:YES];
[picker.view removeFromSuperview];
[picker release];
}
My first question is: What am I supposed to add to this function for viewing the selected photo in the UIImageView? (When I click on the photo from the photo library in the simulator, neither the photo library hide nor the image is viewed in the specified UIImageView)
2- I have read that I should've used UIImage instead of UIImageView.. Is this true? If yes, what about the interface builder? There is nothing called UIImage?
To close the image picker, use:
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
What you get from
bgImage = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
is not an UIImageView, it's a UIImage. To get it displayed, you need to have a UIImageView in your UI somewhere, and set the view's image with what you just got from the picker:
imageView.image = bgImage
Hope this helps