2D Array of UIButtons Isn't Working (Objective-C/iPhone development) - iphone

I've made a bunch of UIButtons in a grid and I want to be able to iterate over them easily so I've put them in an NSMutableArray.
Like so:
// in .h
UIButton* button1;
UIButton* button2;
...
UIButton* button9;
UIButton* myButtons[3][3];
// in init function in app
myButtons[0][0] = button1;
myButtons[0][1] = button2;
...
myButtons[2][2] = button9;
But now if I try to access the title of a button in myButtons I get nil:
// elsewhere in app
[button1 setTitle:#"A" forState:UIControlStateNormal];
// and then:
NSLog(#"currentTitle of button1: %#", (myButtons[0][0]).currentTitle); // -> (null)
Anybody know what's going on? Thanks!

first of all, that's not an NSMutableArray, it's just a plain ol' array.
Second, where do you set button1 to a non-null value? Is it before or after assigning myButtons[0][0] = button1;? I would check and make sure that myButtons[0][0] is non-null when calling the NSLog method. If it is, then you need to assign your array later or assign the buttons earlier.

Related

How To point to an object from string

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
}

iPhone - call UISwitch that is generated in a UIView when a button is pressed

To clarify my question, my program has three lightbulb on the screen (Customized UIButton)
when any lightbulb is pressed, I programatically generate a UIView with a switch on it
when I turn on the switch, corresponding lightbulb will light up (change its background image)
However, I have trouble accessing this UISwitch since I can't declare it publicly
My code goes something like this:
#property buttonA;
#synthesize buttonA;//all three buttons have their background image set to 'off.png'
- (IBAction)lightBulbPressed:(UIButton *)sender
{
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(1,1, 64, 64)];
UISwitch *mySwitch = [[UISwitch alloc] initWithFrame:CGRectMake(0,0,64,64)];
[mySwitch addTarget:self action:#selector(onOrOff) forControlEvents:UIControlEventValueChanged];
[myView addSubview:mySwitch]
[self.view addSubview:myView];
}
So what troubles me is how to program the selector onOrOff, so that it knows which switch is being touched and change the background image of corresponding button accordingly.
Think about your method:
- (IBAction)lightBulbPressed:(UIButton *)sender {
// your method
}
You already know who called it. This piece of information is stored in sender.
So you can save it and use later in onOrOff
By the way, if you are using UISwitch you have to check
UIControlEventValueChanged
and not UIControlEventTouchUpInside.
EDIT: To pass your sender you can store its value to a NSString *buttonTapped declared in your .h file
- (IBAction)lightBulbPressed:(UIButton *)sender {
if (sender == bttOne) {
buttonTapped = #"ButtonOneTapped";
} else if (sender == bttTwo) {
buttonTapped = #"ButtonTwoTapped";
} else if (sender == bttThree) {
buttonTapped = #"ButtonThreeTapped";
}
// your method
}
- (void)onOrOff {
if ([buttonTapped isEqualToString:#"ButtonOneTapped"]) {
// Button One
} else if ([buttonTapped isEqualToString:#"ButtonTwoTapped"]) {
// Button Two
} else if ([buttonTapped isEqualToString:#"ButtonThreeTapped"]) {
// Button Three
}
}
One way to do so, is taht you give them distinct tag numbers in IB, and in - (IBAction)lightBulbPressed:(UIButton *)sender method, get their tag. e.g. NSInteger pressedButtonTag = [sender tag];, and go from there.
Also, instead of alloc/init myView every time user presses a button, you can add that view in IB, add the switch to it, put in the hierarchy of the owner but not the view, and set an outlet to it in .h. Call it whenever you need it, and again, access the switch by tag e.g. ( UISwitch *mySwitch = (UISwitch *)[myView viewWithTag:kSwitchTag]; ) and do whatever you want to do (on or off), add it to the subview and remove it later. This is more efficient.

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 get the name of the button in an action?

I have a button named start and I want to know in the method that it calls what it's name is and I'm not really sure how to do it. This is the method the button calls.
-(IBAction) startMotion: (id)sender {
UIButton * buttonName = (UIButton *) sender;
NSLog(#"Button Name: %#", buttonName.currentTitle);
}
The NSLog prints
Button Name: (null)
You can set the title of the button through
[b setTitle:#"Start" forState:UIControlStateNormal];
and to get the title (currentTitle is read-only and may be nil):
[b currentTitle];
BTW, if you just want to differentiate multiple buttons, you can just set the tag property (an integer value) of the buttons.
Also, check if you have the button specified as an IBOutlet in your viewController class, and is it connected properly as an outlet in Interface Builder?
I would rather set a certain Tag and compare the tag value rather than reading the title of the button since you have possibility to localize your app where button titles will possibly be different.
I was using the wrong property in Interface Builder.I was using name property of button in Interface Builder instead of the title property from the button settings.