Access/Reference imageView.image to replace it later - iphone

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.

Related

UIImage VIew Not loading image?

I have a UIImage on my MyCartViewController. And i have a button on my BlackFacePlatesViewController. I want this button to set the image on the MyCartViewController to another image, however i can't seem to get it to work. Here is my code for the button to set the image on the MyCartViewController:
EDIT:
I HAVE 1 BOOL VARIABLE IN VC2 AND WHEN THE BUTTON IS PRESSED IN VC1, I SET THE BOOL AND CREATE VC2. THEN IN THE VIEWWILLAPPEAR METHOD, I SET THE IMAGE ACCORDINGLY. HERE IS THE CODE: THANKS
- (IBAction)outlet1 {
MyCartViewController * imageCart = [[MyCartViewController alloc]init];
imageCart.displayImage = YES;
}
BUTTON THAT THE USER PRESSES ^
THIS IS TO SWITCH PAGES:
- (IBAction)myCart:(id)sender; {
MyCartViewController * first = [[MyCartViewController alloc]init];
first.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:first animated:YES];
[first release];
}
THIS IS THE VIEWWILLAPPEAR METHOD IN VC2:
-(void)viewWillAppear:(BOOL)animated{
if (self.displayImage == YES) {
UIImage * myImage = [UIImage imageNamed:#"Paddle_3.png"];
[outletImageView setImage:myImage];
}
}
WOULD THIS WORK? THANK YOU VERY MUCH FOR THE HELP EVERYBODY!!!
You aren't allocating your object cart properly, and cart2 has nothing to do with cart, apart from being a similar class. You should just make an instance variable in the header file that's a UIImage which holds the image you want to use in your next UIView, and set it when you use presentModalViewController: Try this. In your .h file,
#interface MyCartViewController : UIViewController {
UIImage * imageForNextView;
}
In your .m file,
- (IBAction)outlet1:(id)sender; {
imageForNextView = [UIImage imageNamed:#"Paddle_1.png"];
}
- (IBAction)outlet2:(id)sender; {
imageForNextView = [UIImage imageNamed:#"Paddle_2.png"];
}
- (IBAction)myCart:(id)sender; {
MyCartViewController * cart2 = [[MyCartViewController alloc]init];
cart2.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
cart2.newImage.image = imageForNextView;
[self presentModalViewController:cart2 animated:YES];
[cart2 release];
}
I made 2 button methods to illustrate the point of switching the image based on which button was pushed. Remember that imageNamed: caches the UIImage, so if you have a lot, you may have to start looking into other loading methods, all of which can be found here. This should solve your problem.
Edit: Try this. In your .h file,
#interface MyCartViewController : UIViewController {
NSString * nameOfImage;
UIImageView * imageView;
}
#property (nonatomic, retain) NSString * nameOfImage;
In the .m file,
#synthesize nameOfImage;
- (void)viewDidLoad; {
[super viewDidLoad];
imageView.image = [UIImage imageNamed:nameOfImage];
}
Then, when you push to the view, try:
- (IBAction)myCart:(id)sender; {
MyCartViewController * cart2 = [[MyCartViewController alloc]init];
cart2.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
cart2.nameOfImage = #"Paddle_2.png";
[self presentModalViewController:cart2 animated:YES];
[cart2 release];
}
Edit2: This is a tutorial about how to use a UISplitViewController, which has a similar idea, where you press a UITableViewCell, and it changes an image in another UIView. You should look through this, and see if it can help your project.
Also, try:
- (IBAction)myCart:(id)sender; {
MyCartViewController * cart2 = [[MyCartViewController alloc]init];
cart2.nameOfImage = #"Paddle_2.png";
[self pushViewController:cart2 animated:YES];
[cart2 release];
}
This is another way to move to a new UIView, which may work.
Hope that Helps!
Are you sure this line of code is actually executed? Did you check that while debugging or with an NSLog?
If not then check the reference to the action 'outlet1'.
What is cart?
What is cart.newimage?
How are those linked to the UIImagaeView that is part of 'the next page'?
You may need to force the redraw via setNeedsDisplay.
Assuming your cart.newImage is the UIImageView object:
[cart.newimage setNeedsDisplay]; //might do the trick.
However, that is a bit view of code to really understand the issue.

How to add button "upload" when using Camera in Iphone?

I have a tableView, and I want to take a picture when clicking in one of the cells and upload it to a certain server.
I have managed to do this so far:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//do actions
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
// Set the image picker source to the camera:
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
// Hide the camera controls:
picker.showsCameraControls = YES;
picker.navigationBarHidden = NO;
// Make the view full screen:
picker.wantsFullScreenLayout = YES;
//picker.cameraViewTransform = CGAffineTransformScale(picker.cameraViewTransform, CAMERA_TRANSFORM_X, CAMERA_TRANSFORM_Y);
// Now insert our overlay view (it has to be here cuz it's a modal view):
//picker.cameraOverlayView = overlayView;
matches *aMatch = [appDelegate.matches objectAtIndex:indexPath.row];
NSLog(#"%#", [NSString stringWithFormat:#"%d", aMatch.match_id]);
// Show the picker:
[self presentModalViewController:picker animated:YES];
[picker release];
}
It starts the camera and takes the picture, but I would like to get an "Upload" button when clicking in "use", can you help me? is it posible? (like the facebook app)
By the way, whe I click in use it comes back to the table view, but where is the image? is it saved in picker?
you get your image in the delegate method of image picker controller
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo
{
//write your code here to save image in ur UIImage object for e.g:-
UIImage *myImage = img;
// add upload button from here or else set it hidden property to false if u have previously created upload button and had set ti to hidden
}
Maybe I didn't explain myself very good, but here is an example of what I was trying to do ( customize the look of the camera by adding an upload button): http://developer.apple.com/library/ios/#samplecode/PhotoPicker/Introduction/Intro.html%23//apple_ref/doc/uid/DTS40010196-Intro-DontLinkElementID_2
Thank you.

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

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.

Multiple UIViews, dealloc and retain

I have a small application for displaying several UIImageViews in a UIScroller in a similar fashion to the Photo app. I have a TableView which, when i select an item, parses an XML document of photos (added to an array) and adds a UIViewController which displays the images.
The problem is I have a tab bar controller which, upon clicking a tab bar item should go back to the TableView after remove the View that displays the images and dealloc all used memory. The problem is I can't work out how to achieve this. Whether it's a lack of understanding the memory rules I don't know.
Here's the process I'm having issues with.
Table View Controller
This is called after parserDidEndDocument:. backToMenu is called from the tab bar item.
#interface AlbumsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
AlbumViewController *albumViewController;
}
#property (nonatomic, retain) AlbumViewController *albumViewController;
- (void)displayPhotos {
albumViewController = [[AlbumViewController alloc] initWithNibName:#"AlbumView" bundle:nil];
albumViewController.parentView = self;
albumViewController.arrPhotos = self.arrCurrentSetOfPhotos;
[self.view addSubview:albumViewController.view];
[albumViewController populateScroller];
}
- (void)backToMenu {
[albumViewController.view removeFromSuperview];
}
Album View Controller
This is a UIViewController containing a UIScroller and UIPageControl. It adds several ImageViewControllers.
- (void)populateScroller {
imagesScroller.pagingEnabled = YES;
imagesScroller.contentSize = CGSizeMake(imagesScroller.frame.size.width * [self.arrPhotos count], 380);
imagesScroller.showsHorizontalScrollIndicator = NO;
imagesScroller.showsVerticalScrollIndicator = NO;
imagesScroller.scrollsToTop = NO;
imagesScroller.delegate = self;
imagesScroller.backgroundColor = [UIColor blackColor];
pageControl.numberOfPages = [self.arrPhotos count];
pageControl.currentPage = 0;
pageControl.backgroundColor = [UIColor blackColor];
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (int i = 0; i < [self.arrPhotos count]; i++) {
CGRect frame = imagesScroller.frame;
frame.origin.x = frame.size.width * i;
frame.origin.y = 0;
NSString *strImagePath = [self.arrPhotos objectAtIndex:i];
ImageViewController *imageViewController = [ImageViewController alloc];
imageViewController.localImage = YES;
[imageViewController initWithPhotoName:strImagePath];
[controllers addObject:imageViewController];
imageViewController.view.frame = frame;
[imagesScroller addSubview:imageViewController.view];
[imageViewController release];
}
self.viewControllers = controllers;
[controllers release];
}
ImageViewController
This has one method. It adds an subclassed UIView called ImageView which handles adding a UIImageView.
- (void)loadImage {
NSString *strRootURL = #"http://www.marklatham.co.uk";
CGRect rect = CGRectMake(0.0, 0.0, 320.0, 480.0);
ImageView *imageView = [ImageView alloc];
imageView.strURL = [strRootURL stringByAppendingString:self.strThisPhoto];
imageView.strTmpPrefix = (self.localImage) ? #"_tmp_rockphotothumb_" : #"_tmp_rockphotolarge_";
[imageView initWithFrame:rect];
[self.view addSubview:imageView];
[imageView release];
}
The backToMenu function is supposed to remove/dealloc AlbumViewController and call delloc on ALL child subviews freeing up the used memory.
Where am going wrong? Any help would be appreciated.
Thanks.
Your AlbumViewController is still holding a reference to the view, so it won't get released until you release that reference. But, this is a good thing.
Don't worry about freeing memory every time the user changes screens. It'll just slow things down as they flip back and forth between different views. If the system gets low on memory, it'll call didReceiveMemoryWarning on all of your view controllers, which will cause them to release their views if they aren't being displayed.
You just want to be a bit more clever about how you allocate/release the albumViewController
- (void)displayPhotos {
////// Only create this view controller if it doesn't exist yet
if(albumViewController == nil) {
albumViewController = [[AlbumViewController alloc] initWithNibName:#"AlbumView" bundle:nil];
}
albumViewController.parentView = self;
albumViewController.arrPhotos = self.arrCurrentSetOfPhotos;
[self.view addSubview:albumViewController.view];
[albumViewController populateScroller];
}
- (void)backToMenu {
[albumViewController.view removeFromSuperview];
//// if you don't do this, you'll have a retain cycle between the two
//// view controllers and neither will ever get released
albumViewController.parentView = nil;
}
- (void)didReceiveMemoryWarning {
///// if the albunViewController isn't in use, go ahead and free its memory
if([self.albumViewController isViewLoaded] && self.albumViewController.view.superview == nil) {
self.albumViewController = nil;
}
[super didReceiveMemoryWarning];
}
Also, instead of calling populateScrollers from AlbumsViewController, call it in the setArrPhotos method of AlbumViewController, but only if arrPhotos has changed. For example:
- (void)setArrPhotos:(NSArray *)newArrPhotos {
if(newArrPhotos != arrPhotos)
{
[arrPhotos release];
arrPhotos = [newArrPhotos retain];
[self populateScrollers];
}
}
This way, if the user goes to view the same album over and over again, you won't recreate the same view hierarchy over and over.
After convincing my client I managed to get around this by going with the three20 framework.

UIImagePickerController weirdness

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 ??