I have a problem with my application. It crashes after few times of working with images and I have no idea why.
I have a TabBar, in one item of TabBat I have a navigation controller. In the root controller of that navigation I have a two buttons. One button is to get an image from camera or photo library, the second button is to get an image from saved images in the app. With selected image I go to next view controller (SelectImageViewController).
With the first button I use that code:
- (void) showImagePickerWithSourceType:(NSInteger) sourceType
{
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = sourceType;
picker.allowsEditing = NO;
[self presentModalViewController:picker animated:YES];
[picker release];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *selectedImage = (UIImage *)[info objectForKey:#"UIImagePickerControllerEditedImage"];
if (selectedImage == nil)
selectedImage = (UIImage *)[info objectForKey:#"UIImagePickerControllerOriginalImage"];
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
SelectImageViewController *selectImageViewController = [[[SelectImageViewController alloc] initWithImage:selectedImage] autorelease];
[self.navigationController pushViewController:selectImageViewController animated:YES];
}
With the second button I use:
DocumentsViewController *documentsViewController = [[[DocumentsViewController alloc] init] autorelease];
[self.navigationController pushViewController:documentsViewController animated:YES];
DocumentsViewController is a TableViewController with list of images, when I select one image than I go to the SelectImageViewController.
In SelectImageViewController I make some image processing and then go to next view controller where I make another image processing.
Here is some code from SelectImageViewController:
- (id) initWithImage:(UIImage *) image
{
self = [super init];
if (!self) return nil;
self.originalImage = image;
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor grayColor];
[NSThread detachNewThreadSelector:#selector(processImage) toTarget:self withObject:nil];
}
- (void) processImage
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
self.originalImage = [ImageHelper scaleAndRotateImage:self.originalImage toSize:CGSizeMake(1500, 1500)];
self.processedImage = [ImageHelper scaleImage:self.originalImage maxWidth:320 maxHeight:367];
[self performSelectorOnMainThread:#selector(finish) withObject:nil waitUntilDone:NO];
[pool release];
}
- (void) finish
{
imageView = [[UIImageView alloc] initWithImage:self.processedImage];
imageView.center = self.view.center;
[self.view addSubview:imageView];
[self.view sendSubviewToBack:imageView];
[NSThread detachNewThreadSelector:#selector(processImage2) toTarget:self withObject:nil];
}
- (void) processImage2
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSArray *corners = [OpenCV processImage:self.processedImage];
[self performSelectorOnMainThread:#selector(finish2) withObject:nil waitUntilDone:NO];
[pool release];
}
In the SelectImageViewController I have one button and when I click it I process the original image and then go to the next view controller.
In the last view controller in viewDidLoad method I process one more time the image.
I know that all method for image processing take a lot of memory and some time (especially that my original image which I use often is not scaled), but the application also crashes when I only select an image from photo library and go to SelectImageViewController. Maybe I shouldn't use a navigation controller? Has anybody an idea what can be wrong?
Thanks for any help.
Take care about the autorelease. Functions usually return autorelease objects. You are within an autorelease pool so, it is possible that the image wont exists when you call the last selector. Try assigning the images by using de setter method
[self setProcessedImage:[ImageHelper scaleImage:self.originalImage maxWidth:320 maxHeight:367]];
only if you have declared your variable as an instance property with retain or copy, it will retain the image.
Use NSZombieEnabled to see what happens. It seems to be a classic problem of a freed object.
Related
I am trying to display a UIImagePicker from a programatically generated UIView that's added as a subview of the original view controller. The image picker comes up and so does the camera but the functionality breaks and nothing navigates properly. How do I properly load an image picker from a UIView and not a UIControlView?
code that breaks:
- (void)captureImage:(id)sender
{
[[[UIActionSheet alloc] initWithTitle:nil
delegate:self
cancelButtonTitle:#"Close"
destructiveButtonTitle:nil
otherButtonTitles:#"Take photo", #"Camera Roll", nil]
showInView:self];
}
//UIImagePicker specific methods
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
switch (buttonIndex)
{
case 0:
[self takePhoto];
break;
case 1:
[self fromCameraRoll];
break;
}
}
-(void)takePhoto
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] == YES)
{
// Create image picker controller
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
// Set source to the camera
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
// Delegate is self
imagePicker.delegate = self;
// Show image picker
[self addSubview:imagePicker.view];
}
}
-(void)fromCameraRoll
{
UIImagePickerController *imgPicker = [[UIImagePickerController alloc] init];
imgPicker.delegate = self;
imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self addSubview:imgPicker.view];
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// Access the uncropped image from info dictionary
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
//do something with the image
//add code to pick images here and store them in the preview
[picker dismissModalViewControllerAnimated:NO];
}
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[picker dismissModalViewControllerAnimated:NO];
}
UIImagePickerController is view controller class, you better present your image picker to your parent view controller by a delegate call or something like with an overlay subview to achieve your goal.
UIImagePickerController *imgPicker = [[UIImagePickerController alloc] init];
imgPicker.delegate = self;
imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
CustomOverlayView *overlayview = [[CustomOverlayView alloc] init];
imgPicker.cameraOverlayView = overlayview;
[self presentModelViewController:imgPicker animated:YES];
add another delegate in your overlay class to dismiss your camera picker controller view
[imgPicker dismissModelViewControllerAnimated:YES];
when the bar button item is tapped the popover view shows fine but it does not dismiss when a photo is selected. Am I missing something? What should i do?
-(IBAction)addPhoto:(UIBarButtonItem *)sender
{
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
popover = [[UIPopoverController alloc] initWithContentViewController:imagePicker];
[popover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)selectedImage editingInfo:(NSDictionary *)editingInfo
{
// Delete any existing image.
NSManagedObject *oldImage = imageClass.image;
if (oldImage != nil)
{
[imageClass.managedObjectContext deleteObject:oldImage];
}
// Create an image object for the new image.
NSManagedObject *myImage = [NSEntityDescription insertNewObjectForEntityForName:#"Image" inManagedObjectContext:imageClass.managedObjectContext];
imageClass.image = myImage;
// Set the image for the image managed object.
[image setValue:selectedImage forKey:#"image"];
[popover dismissPopoverAnimated:YES];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[[picker parentViewController] dismissViewControllerAnimated:YES completion:nil];
}
The issue is that you are trying to dismiss the image picker controller but you need to dismiss the popover that it is in. Things need to be dismissed based on how they were presented.
Change:
[self dismissViewControllerAnimated:YES completion:nil];
to:
[popover dismissPopoverAnimated:YES];
Calling dismissViewControllerAnimated:completion: would be used if you have called presentViewController:animated:completion:.
To dismiss UIPopoverViewController on the selection of a photo from gallery, you need to add following lines in didFinishPickingMediaWithInfo method after picking an image.
- (void)imagePickerController:(UIImagePickerController *)imagePicker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[popover dismissPopoverAnimated:YES];
[imagePicker dismissModalViewControllerAnimated:YES];
}
You've not set delegate of imagePicker to self. Plus you need to take popover as instance variable to dismiss in delegate method.
1) in you .h you must add <UIImagePickerControllerDelegate>
2) add imagePicker.delegate=self; so your addPhoto method should look as below:
-(IBAction)addPhoto:(UIBarButtonItem *)sender {
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate=self; //add this line to your code
popover = [[UIPopoverController alloc]
initWithContentViewController:imagePicker];
[popover presentPopoverFromBarButtonItem:sender
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
just give the delegate UIPopoverControllerDelegate and UIImagePickerControllerDelegate in .h file
you must add UIImagePickerControllerDelegate to your corresponding .h file and also Check this Code
-(IBAction)addPhoto:(UIBarButtonItem *)sender
{
UIImagePickerController *imagePicker3 = [[UIImagePickerController alloc] init];
imagePicker3.delegate = self;
imagePicker3.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker3.allowsEditing = YES;
imagePicker3.mediaTypes = [NSArray arrayWithObject:#"public.image"]
[self presentModalViewController:imagePicker3 animated:YES];
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[self dismissModalViewControllerAnimated:YES];
_imageselected.image=[info valueForKey:UIImagePickerControllerEditedImage];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[self dismissModalViewControllerAnimated:YES];
}
In case someone is still experiencing this infamous error when using UIImagePickerController:
Assigning to 'id <UINavigationControllerDelegate,UIImagePickerControllerDelegate>' from incompatible type 'DetailViewController *const __strong'
try to move
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
to the
- (void)viewDidLoad{
//do your stuff
}
and don't forget to include the delegate protocol definitions (<UINavigationControllerDelegate,UIImagePickerControllerDelegate>) in the corresponding .h file.
This solved my problem, hope it's gonna help someone else. Don't know if its the best solution, but worked for me in a similar case.
Basically, through the use of a custom overlay with the camera app, I am wanting multiple images (in my case 5) to be taken, with only one press of a 'capture' button.
I understand that the following code:
- (void)takePicture:(id)sender
{
self.pictureButton.enabled = NO;
[self.delegate takePicture];
}
results in a single image being taken. Is there a way to have this action replicated 5 times, after a single button press? Effectively, this would achieve a 'burst' like effect, as is implemented in the Camera+ app.
Try this code it take 5 pictures from camera and store in an array. use as you need.
int counter;
NSMutableArray * imageArray;
-(void)takePicture
{
counter=0;
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
[imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera];
[imagePicker setDelegate:self];
[self presentModalViewController:imagePicker animated:YES];
[imagePicker release];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image= [info objectForKey:UIImagePickerControllerEditedImage];
[imageArray addObject:image];
counter++;
if (counter<5)
{
[self dismissModalViewControllerAnimated:NO];
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
[imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera];
[imagePicker setDelegate:self];
[self presentModalViewController:imagePicker animated:NO];
[imagePicker release];
}
else
{
[self dismissModalViewControllerAnimated:YES];
}
}
I have a hierarchy of views:
compView with two children:
bgView
objectView.
I'm passing objectView to the cameraOverlayView property of the UIImagePickerController. Once the ImagePicker is done I update the image in the bgView and I would like to continue to display the view tree including the objectView which was passed to the UIImagePickerController as an overlayView.
The problem is that after calling dismissModalViewControllerAnimated to close the UIImagePickerController, the objectView is not appearing, as if the UIImagePickerContoller is hiding it. I checked in the debugger and it doesn't seem to be dealocated. The pointer is still valid. But the view is not showing.
Any ideas of what I might be doing wrong?
Thanks,
Eddy
Here a bit of code to show you what I'm doing:
From myViewController.m:
- (void)loadView {
CGRect rect = self.navigationController.view.bounds;
compView = [[UIView alloc] initWithFrame:rect];
bgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Storage/dummy_bg.png"]];
objectView = [[PropImageView alloc] initWithImage:[UIImage imageNamed:#"Storage/rasta.png"]];
[objectView setUserInteractionEnabled:YES];
[objectView setMultipleTouchEnabled:YES];
[compView addSubview:bgView];
[compView addSubview:objectView];
self.view = compView;
[self placeObject];
[objectView release];
[bgView release];
[compView release];
}
- (void) placeObject
{
NSLog(#"camera button pressed");
// make sure camera is avaialble before setting it as source
//
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
#if !TARGET_IPHONE_SIMULATOR
UIImagePickerController* picker = [[UIImagePickerController alloc] init];
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.delegate = self;
picker.allowsEditing = NO;
picker.view.hidden = NO;
picker.cameraOverlayView = objectView;
[self presentModalViewController:picker animated:NO];
[picker release];
#endif
}
// from PickImageAppDelegate.m
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo
{
// Dismiss the image selection, hide the picker and
[picker dismissModalViewControllerAnimated:YES];
bgView.image = [self rotateImage:image byOrientationFlag:UIImageOrientationRight];
}
[picker dismissModalViewControllerAnimated:YES];
That should be
[self dismissModalViewControllerAnimated:YES];
I've got a very simple app where the user selects a UIImageView and presses a button to take a photo with the camera. The image is then returned and displayed in the UIImageView.
However, since the UIImageViews are sharing the same delegate, when there's already an image in one of the UIImageViews, and I go to take a photo to be placed in another, the previous UIImageView is replaced with empty content (i.e. no image). I guess this is because they're sharing the same delegate. Is there any way I can essentially copy the image instead of referencing the delegate version of it?
Here's some sample code:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo {
[picker.parentViewController dismissModalViewControllerAnimated:YES];
if (topView == YES)
{
NSLog(#"topView = %i", topView);
imageView.image = image;
}
else {
NSLog(#"topView = %i", topView);
imageView2.image = image;
}
}
Thanks!
Edit: Here's the code that gets called by the IBAction on the button presses
- (IBAction) pushPick {
topView = YES;
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:picker animated:YES];
[picker release];
}
- (IBAction) pushPick2 {
topView = NO;
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:picker animated:YES];
[picker release];
}
Something like this:
UIImage * newImage = [UIImage imageWithCGImage:[image CGImage]];
use
[image copy];
But remember that you will need to release the object on dealloc