How To point to an object from string - iphone

My question is kind of general; in my project I have 10 UIButton objects
named Button1, Button2, Button3, Button4, Button5, Button6, Button7, Button8, Button9, and Button10
I also have UIImageview That are named exactly like the buttons from 1 to 10.
I want to write a code that will manipulate the image by the last character of the button (always a number from 1 to 10) and will affect the UIImageview the same way
Something like this
buttonlastcharacter = i;
if(sender.lastcharacternumber is:i){
Button%,i.frame = //Some manipulation
But basically all that I want is to have access to a certain object by string
How can I implement such a behavior?

There are a couple of better ways to do this. If these buttons are all static and in IB you can use an IBCollection array for image views and buttons to simply call them up by matching indexes.
Better yet just use the tag value for the buttons or image views.

It is maybe not the ideal solution in your case, but you can do it different ways:
using kvo
UIButton* myButton = [self valueForKey:[NSString stringWithFormat:#"button%i",i]];
or with selectors and properties
UIButton* myButton = [self performSelector:NSSelectorFromString([NSString stringWithFormat:#"button%i",i])];

Hm, you could use an array for your buttons and a tag for your UIImageView objects. They all inherit from UIView, which provides you with a .tag propterty. It is of type NSInteger* .
For convenience reasons I would suggest to name the buttons from 0 to 9. It does not really matter but the first index in the array would be 0 and therefore naming them accordingly just makes things easier.
Define
NSArray *buttonArray;
You may opt for NSMutableArray depending what else you may want to do with it.
In viewDidLoad code:
buttonArray = [NSArray arrayWithCapacity:10];
buttonArray[0] = button0;
..
buttonArray[9] = button9;
In your XIB file in Interface Builder, or whereever you may create the UIImages programmatically, add the tags accordingly.
image0.tag = 0;
...
image0.tag = 9;
assuming you name them image0 to image9.
In your appropriate action method code:
buttonArray[sender.tag] = someManipulation;

You can do it like this,
In your IBAction method:
- (IBAction)click:(id)sender
{
UIButton *but = (UIButton *)sender;
but.frame = your manipulation code;
}
or you can check the title like:
if([but.currentTitle isEqualToString:#"Button1])
{
//Manipulate button 1
}
if you have added tags for the buttons from 1-10 you can use,
if(but.tag == 2)
{
//Manipulate button 2
}

Related

Control more than one button using tags

I have 28 buttons in my application. I need to control them in a single function. All I want to do is make all the buttons visible. I gave tags to the buttons. I tried it with a for loop but I couldn't do it how can I solve this problem?
(IBAction)btnAction:(id)sender{
UIButton *btnPressed = (UIButton *)sender;
NSUInteger i=btnPressed.tag;
for(i=0; i<29; i++)
{
btnPressed.hidden=NO;
}
}
Instead of tags, use an IBOutletCollection. So now you have a single NSArray pointing to all of the buttons. Now just cycle through that NSArray.
You can create a single IBAction method, check tag values and then do what you want to do
- (IBAction)btnAction:(id)sender{
UIButton *btnPressed = (UIBUtton *)sender;
// Check button tags and write code accordingly //
}
use IBOutletCollection. see the following link for your answer.
IBOutletCollection
and
IBOutletCollection (UIbutton)
IBOutletCollection of UIButtons - changing selected state of buttons

Cast NSString to UIButton type

Im trying to cast a string to a button type. Basically, Im looping through, say 5 buttons, named btn1,btn2..btn5. Here's the snippet:
- (IBAction)replaceImg
{
UIButton* b;
for(int i=0; i<5; i++)
{
b = (UIButton*)[NSString stringWithFormat:#"btn%d",i]; //1!
if([b isHighlighted])
{
int imgNo = (arc4random() % 6) + 1;
UIImage *img = [UIImage imageNamed:[NSStringstringWithFormat:#"%d.png", imgNo]];
[b setImage:img forState:(UIControlState)UIControlStateNormal];
}
}
}
The line marked 1 is giving a problem, if I swap it with b = btn1, it works perfectly. Please help!
I couldnt find a way to access a button by its name either. Like UIImage has something like imageNamed.
you can't cast NSString to UIButton because both are completely different type.
Use tag property of UIView to assign and unique number to each UIButton and at any point of time you could access them by using viewWithTag .
You can't 'cast' an NSString to a button. To get specific buttons, or buttons by name, depends on how you created them. Store your created buttons into an array, or if they come from a NIB then gather their pointers into an array, then loop through the array of button pointers. Controls are also UIViews, so you can assign a numeric 'tag' to each button in Interface Builder then use UIView's viewWithTag: method to search for a specific view with a specific tag.
An NSString isn't a UIButton, so casting it to one isn't going to work. Well, it might work as far as syntax goes, but logic-wise, it will fail. You simply cannot interact with an NSString the same way you can a UIButton. If you need to find your button by name, then you can either retain pointers to those buttons (either in an array, a map, or just as plain instance variables, to name a few ways), or you could alternatively use something like viewWithTag:.

Is it possible to add a second tag to an UIbutton?

I was wondering if it is possible to add a second tag to a UIButton? I've created a number of buttons programatically in a for-loop and need a reference to the number of the button (e.g. 0, 1, 2) and another reference (integer) in which I store a reference to the page the button links to (e.g. 22, 30, 49). The numbers are not related so I can't determine the first through the second.
This is what I'd like to have:
for (int k=0; k < numberOfTabs; k++) // k < 4 (e.g. 3 < 4)
{
UIButton* btn = [[[UIButton alloc] initWithFrame:frame] autorelease];
btn.tag = k;
btn.tag2 = someReference;
btn.frame = CGRectMake(-10, 0, buttonWidth, buttonHeight);
[btn addTarget:self
action:#selector(tabAction:)
forControlEvents:UIControlEventTouchUpInside];
[btn addTarget:self
action:#selector(tabDelete:)
forControlEvents:UIControlEventTouchDragOutside];
/...
Any suggestions would be very much appreciated.
No you cant. Not directly at least. You can subclass UIButton and add another int property but that seems like an overkill for what you want..
I think it would be better to just decide on how you can fit both the values in the single tag integer...
e.g. if you have pageNumber and buttonNumber you can create the buttons tag like:
button.tag = pageNumber*100 + buttonNumber;
and when you want to which page a button belongs to or what is the index of a button on a page, you can dacode the tag:
int pageNum = button.tag /100;
int buttonNum = button.tag % 100;
Create a subclass of UIButton with your second tag declared as property.
You could as well create an array to map the tag of your button to a page, which would prevent creating a subclass but will introduce some array management method.
I'd prefer the array solution, as I try to prevent subclassing whenever I can.
Why not store the second (any more, if needed) parameters in something like an NSMutableArray?
NSMutableArray *button_to_page = [[NSMutableArray alloc] init];
...
for(...)
{
// Your button creation code
[button_to_page addObject:[NSNumber numberWithInt:my_button.tag];
}
You can get your page number at any time by simply indexing into the button_to_page array.
You can also search the array for a page number and get the button index (if needed).
Now, having said that, here you are creating a new NSNumber object for each button's page tag and also carrying around an NSMutableArray to boot. I really think that subclassing UIButton is the way to go. I don't like the idea of encoding stuff into the single tag unless there's a real compelling reason. If you subclass you are still keeping the UIButton pretty lightweight and all your data is encapsulated within the same object very cleanly:
MultiTag_UIButton.h
#import <Foundation/Foundation.h>
#interface MultiTag_UIButton : UIButton {
}
#property (nonatomic, assign) int page;
#end
MultiTag_UIButton.m
#import "MultiTag_UIButton.h"
#implementation MultiTag_UIButton
#synthesize page;
#end
It really is that simple, you don't have to write any code, just add the page property and you are off to the races. Then you can do this:
MultiTag_UIButton *test_button = [[MultiTag_UIButton alloc] init];
test_button.tag = 1;
test_button.page = 23;
NSLog(#"tag %i page %i", test_button.tag, test_button.page);
[test_button release];
Clean and simple. Realistically you'd have to do a little more in the new class, but you get the idea.
According to what I can see looking at Apple's documentation for UIView where the tag property is defined (since UIButton inherits from UIView), it appears you can only have the one.
There's nothing stopping you from subclassing UIButton to add another tag property if necessary as mentioned.
You could subclass, but then when you handle it (if you intermix it with non subclassed buttons), you are going to have to ask the object if it is is the new object type or implements the new accessor to get at it, which is a bit unpolymorphic.
What about if you just leave the class as is, but partition up the existing bits of the tag so that the lower 16 bits are for one purpose and the upper are for your other purpose? Nothing changes interface wise, you just do some masking on the .tag to get your values.

Access UIButtons like buttonName+i

I'm trying to change the properties of various UIButton that I have declared as follows:
UIButton * button1; UIButton *
button2; ....
It's possible to access them in a similar way to this?
[button+i setTitle:#"button"
forState:UIControlStateNormal];
The variable "i" would be an integer to distinguish one from button from another.
you need to use the tag property of UIButton, which is an integer
EDIT to show tag property
UIButton* myButton .... // whichever way your button is init'd
// set the tag
myButton.tag = 2; // or i or whatever way you set it the property is an int
// get the tag
int y = myButton.tag; // set y to the tag value of the button
its that easy
Do you have lots and lots of button?
Okay, the immediate best way I can think of is something I have put into practice when I had something like 30+ buttons on a screen (it was a calendar).
I created an array into which I put the button then accessed them like this (or something like this)
for (UIButton* b in myBigArrayOfButtons) {
[b setTitle:#"button" for State:UIControlStateNormal];
}

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];
}