Select multiple images - iphone

I have this UITableView which is displaying images, downloaded rom a database, as a matrix: 4 images in each table row.
To be able to select images from the views I'm using a UITapGestureRecognizer. To make each selection unique I've been trying to tag each tap recognizer and each imageView. That's where the problem is...
I've put a log within the for-loop that is creating and tagging the imageViews and recognizers and I can see in the output that they pass through all the values. However when I try to get the tag by later pressing an image I always get "3" (the last number in the table row). This makes me think the tags are simlpy overwriting eachother even though I'm creating a new object in each loop. Either that or I'm reading it out the wrong way.
Unrelated parts cut out.
for (NSInteger i = 0; i < 4; i++){
asyncImage = [[AsyncImageView alloc]
initWithFrame:frame];
[asyncImage loadImageFromURL:url];
asyncImage.tag = i;
NSLog(#"TAG %d", asyncImage.tag);
tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap)];
tapRecognizer.view.tag = i;
NSLog(#"TapTAG %d", asyncImage.tag);
[asyncImage addGestureRecognizer:tapRecognizer];
}
And the method:
- (void)handleTap{
NSLog(#"TAP %d", self.tapRecognizer.view.tag);
}
If you think I'm doing it all totally wrong, a light push in the right direction is always welcome!
Thanks in advance, Tom

The following line has no effect until the gesture recognizer has been added to a view:
tapRecognizer.view.tag = i;
This is because tapRecognizer's view is initially nil. Make the assignment on the last line of your for loop to correct this problem.
Also your NSLog is always showing the tag of the last recognizer that you have added
self.tapRecognizer.view.tag // Instance variable
not the one that fired the event. Change handleTap as follows:
- (void)handleTap:(UITapGestureRecognizer*) tapRecognizer{
NSLog(#"TAP %d", tapRecognizer.view.tag);
}
You should also replace the tapRecognizer instance variable with a local variable in the method that adds the recognizer to the view, and add a colon : to your selector name:
action:#selector(handleTap:)
// HERE: ----^

I think you're doing it wrong in the loop.
Your loop is run 4 times and every time you run the loop you store AsyncImageView to the asyncImage variable (local or instance?). So the first time you run the loop, you create an object and store it at the asyncImage location, the second time this is overwritten, the third....
You have initialized 4 ImageViews, but you are only referencing to the last one. And the last one holds the correct GestureRecognizer, you want.
When do you add the ImageView to a view?
If you use the instance varable and overwrite it directly, all the other ImageViews you added to the screen point to the pointer of asyncImage. And the pointer - after running 4 times the loop and exchanging asyncImage data - points to the last image in the loop.
Hope you understand, what the problem is here.

Related

How do i properly discard a subview?

I have a problem with my app where the code for which is far too long to go into, but suffice to say when i'm removing a UIView and replacing it with a new one like so:
NSLog(#" .. %#", (Icon *)[self viewWithTag:index]);
Icon *icon = (Icon *)[self viewWithTag:index];
CGRect frame = icon.frame;
int tag = icon.tag;
[icon removeFromSuperview];
[icon release];
Icon *icon2 = [[Icon alloc] init];
icon2.frame = frame;
[icon2 makeIconStandardWithTag:(int)tag];
[self addSubview:icon2];
It does some weird thing where that NSLog the first time (because the view is already there) shows that the object is an icon, but the second time after running this code shows that it's a UIImageView for some reason now, and it displays what i presume to be the original icon at some odd position on the screen. It's very erratic behaviour. But what i do know is this:
Removing the [icon removeFromSuperview]; line, although keeping the object there, stops this behaviour and causes the NSLog to return an Icon, as it should.
So my guess is that it's not removing icon correctly. Is there a way to completely remove icon, or is removeFromSuperview as far as i can go. What i could do is just have it set to alpha = 0 but this is more of a patch-over solution and not how i want to solve it.
"Is there a way to completely remove
icon, or is removeFromSuperview as far
as i can go"
You can set the object to nil:
icon = nil;
Can you verify what "self" is in this line of code:
It might not be what you think.
[self addSubview:icon2];
NSLog(#" Self is %#", self);
This is a guess, but try setting self.tag to -1 or some other value that doesn't collide with the tags you're setting on your Icon objects. The viewWithTag: method searches the current view and its subviews for a match, so if self.tag == 0 and you call [self viewWithTag:0], you'll get self.
Did you retain icon somewhere prior to this? If not, no need to release it after the call to removeFromSuperview. Similarly, unless you need the reference to icon2 elsewhere, you can release that after calling addSubview.
Views retain views added via addSubview, and they release views removed via removeFromSuperview.

How to remove everything fron the superView and not just the last item?

In my app i had to draw certain checkboxes at a same time and i used a single function to add all of them. Now when a user clicks one of them all of those checkboxes should get removed from the superview and currently its just removing the last one. Also i have issue to recognize those checkboxes like which one is clicked. i know it should be done through Tag property but don't know how exactly it should be implemented.
Any suggestions.
Removing all subviews
int numberOfSubviews = [[yourView subviews] count];
for(int i=0;i<numberOfSubviews-1;i++
{
[[youView subviews]objectAtIndex:i]removeFromSuperView];
}
//this will leave check box that you added at last.... for first one to remain loop from 1 to numberOfSubviews....
Using tag property...
when you are creating checkbox objects use
checkBoxObject.tag = i;
//I am considering i as looop count which you are using in a loop
to add checkboxes.
then whenever you need a object of checkbox
[yourViewonwhichYouAddedCheckBox viewWithTag:<your tag >];
Thanks
For identifying a "checkbox" or better said any view within an action-method:
- (void)someActionHandler:(id)sender
{
UIView *actionOriginView = (UIView *)sender;
NSLog(#"this action came from view:%d", actionOriginView.tag);
}
For assigning the tag, you may use the IB or within your code, while instantiating;
UIView *myFunkyView = [[UIView alloc] initWithFrame:CGRectZero];
myFunkyView.tag = 1337;
For removing a bunch of views from your superview - lets assume their tag is set to 10 - 15;
for (int i=10;i <= 15;i++)
{
UIView *childView = [superview viewWithTag:i];
[childView removeFromSuperview];
}

How can I see the intermediate updates on my UI while debugging iPad code?

I am developing an app in which I am using a plist file. There are 21 key-value pairs in the plist. Each pair is a dictionary (type) with 6 items. The dictionary contains a set of images. In my program, I am using the path to retrieve the images. My requirement is that the images should be displayed one-by-one on the imageView. i have done it successfully. The images are being dispalyed exactly from plist.
So my question is can I use the debugger to see the intermediate execution of the plist? When I placed breakpoints in my code, and run using the debugger, I am able to step into the code and the images are displayed on the view only after the whole execution of plist with 21 key-value pairs is done. How can I see the images on the view while debugging each pair?
(void)setSequenceInfo:(NSDictionary *)sequenceInfo
{
[self.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
self.sequenceQueue = [NSMutableArray array];
//load the sequenceinfo dictionary
[_sequenceInfo release];
if (!sequenceInfo)
return;
_sequenceInfo = [sequenceInfo retain];
//create one UIImageView by sequence
NSMutableDictionary* views = [NSMutableDictionary dictionaryWithCapacity:[sequenceInfo count]];
for (NSString* identifier in _sequenceInfo)
{
UIImageView* seqView = [[UIImageView alloc] initWithFrame:self.bounds];
seqView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
seqView.contentMode = self.contentMode;
//the image is hidden until its sequence is played
seqView.hidden=YES;
//add the newly created image view to our subviews
[self addSubview:seqView];
//also store it in our sequenceViews dictionary
[views setValue:seqView forKey:identifier];
[seqView release];
}
self.sequenceViews = views;
}
In order to "see" intermediate results while using the debugger, you'll have to change the structure of your code to return to the main run loop, so that the UIImageView has the chance to run and display the new image. You could set up a timer that fires periodically, and in the timer routine you change the UIImageView's image to the next one in the sequence. Then you set your breakpoint in the timer handler method in gdb, and when you hit that breakpoint each time you should see the previously displayed image.
EDIT: here's some more detail, based on what I think you want to do. Realize, though, that I think there's no "magic wand" to be able to see changes on the screen while you're in the debugger. You have to return to the Run Loop so that your UIKIt widgets get cycles to draw themselves.
For example, say you have this method:
- (void) updateTwoLabels:(NSString *)newText
{
self.label1.text = newText;
self.label2.text = newText; // put breakpoint on this line
}
and you want to stop in the debugger just before label2's text is set, and see that label1 has changed. Well, I think there's no way of doing that, except by modifying your code, and calling yourself again with performSelector:withObject:afterDelay: so that the main run loop can run for a while then call your code again:
BOOL callAgain = NO;
BOOL setLabel2 = YES;
- (void) updateTwoLabels:(NSString *)newText
{
self.label1.text = newText;
if ( setLabel2 )
self.label2.text = newText; // put breakpoint on this line
if ( callAgain )
[self performSelector:#selector(updateTwoLabels:) withObject:newText afterDelay:0];
}
in this way, when you're debugging, you can set callAgain to YES and setLabel2 to NO in gdbg, and keep "continuing" until you see that label1 has changed. That's the basic technique.
Do the whole method in a background thread but call GUI stuff on the main thread. For example: [self performSelectorOnMainThread:#selector(addSubview:) withObject:seqView waitUntilDone:YES]. Don't forget to make an autorelease pool at the beginning of the method (the one that runs in the background thread) and drain it at the end of it.

UIImage and UIImagePicker and UIImageView

I have a UISegmentedControl and I have some photos, my initial aim is when ever I click on a particular segment one particular image should appear on the view.
For example: If i have four segments and four images then upon each segment I click I must see a image.
Here I have taken an NSArray and Uploaded all these images using this particular below code:
NSArray * images = [NSArray arrayWithObjects:[UIImage imageNamed:#"f.ppg"], [UIImage imageNamed:#"t.ppg"....etc ], nil];
and after this I want to attach each particular image to a segment index. So here is the code which I wrote.
-(IBAction) segmentActionChanged:(id)sender
{
int segment = mSegment.selectedSegmentIndex;
mImageView.image=[images objectAtIndex:segment];
}
While compiling the application I am not getting any Images displayed and it is quiting abruptly.
Any help regarding this.
To Answer questions 1 and 3 (I think).
to display an image, you will need a UIImageView somewhere. a simple way to do this would be to create an method such as this.
//somewhere in viewDidLoad perhaps?
//title array is an array of strings to use as the label on each section of your control
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:titleArray];
//this sets the segmentAction: method as the selector for your particular UISegmentedControl
//(so when its value is changed, segmentAction: gets called)
[segmentedControl addTarget:self action:#selector(segmentAction:) forControlEvents:UIControlEventValueChanged];
//the segmentAction: method
- (IBAction) segmentAction:(id)sender
{
//This assumes you have declared the imageView elsewhere, as well as the array and that you
//are using Interface Builder to create/hookup the segmentControl. Basically
myImageView.image = [myImageArray objectAtIndex:sender.selectedSegmentIndex];
}
A few Notes: this does not take advantage of lazy loading, since you are creating and holding all of your images in an array prior to showing them. I would suggest creating an instance variable for the UISegmentedControl so you can access it anywhere also.
Disclaimer: this code is not complete and assumes some initializations.
To answer question number two:A UIImagePickerController is used when dealing with the phone's/devices camera or saved photos album. It is covered in the documentation.
Looks like you're missing a retain.

How do I name a file differently everytime I allocate it?

The Code:
// Inside my BoardsViewController.m
- (void)createImage {
imageCounter ++;
board = [[Boards alloc] init];
[self.view addSubview:board];
[board release];
board is supposed to be changed everytime, and is instead of being named board: be named 1_board, 2_board, 3_board, everytime I call this method
}
I want to have the Boards(UIView subclass) have the name of imageCounter, and also have board. Kinda like: 1_board. Meaning I want to have a Boards called something different everytime I call this method.
EDIT:
This should help maybe:
I want to have this one method that I will call multiple times allocate a Board(subclass of UIView) but have them all different names other than only one name. Meaning I increment the view counter everytime before allocating the view. So I want to have the name include the variable inside the integer: viewCounter. So that I cal call the different views seperatly and control each allocation differently.
It is not clear what do you want to achieve. If you want to distinguish between different Board instances later you can use a tag property (available in all UIView subclasses):
- (void)createImage {
imageCounter ++;
Boards *board = [[UIImageView alloc] init];
board.tag = imageCounter;
[self.view addSubview:board];
[board release]; // Note that you need this line also, you current code produces memory leak
}
Later you can get each of the created Boards using:
Boards* yourBoard = [self.view viewWithTag: someTag];
You can also define some custom identifier in your Board class if you want. Changing the name of the local variable (e.g. board to whatever_board) does not really make sense as this name will not be accessible outside of the scope of this function anyway.