Creating UIButtons dynamically - Logic Error - iphone

I have a NSMutableArray, and i have saving some string values in it. The size of the NSMutableArray could vary from 2-5 (Meaning it might have 2 -5 string values stored in it).
Depending on the count of the NSMutableArray i need to initialize UIBUttons and then set the value of the String stored init to the buttons title.
int numberOfButtonsToBeInitialize= [mutableArr count];// we are finding the number of buttons to be initialize and we assign it to a variable.
Now i need to create buttons (what ever the number returned by numberOfButtonsToBeInitialize)
How can i do this ?

for(int i=0;i<numberOfButtonsToBeInitialize;i++){
//init the button
UIButton *bout = [UIButton buttonWithType:UIButtonTypeRoundedRect];
//set the title
[bout setTitle:[mutableArr objectAtIndex:i] forState:UIControlStateNormal];
[bout addTarget:self action:#selector(event:) forControlEvents: UIControlEventTouchUpInside];
[self.view addSubview:bout ];
//then you can set the position of your button
[bout setFrame:CGRectMake(70,3, 40,40)];}

Try this:
NSMutableArray *myButtonsArray = [[NSMutableArray alloc] initWithCapacity:0];
UIButton *tmpButton;
for (NSString *bTitle in mutableArr)
{
tmpButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[tmpButton setTitle:bTitle forState:UIControlStateNormal];
// Any additional setup goes here
[myButtonsArray addObject:tmpButton];
}
Now you have an array with all the buttons. You can just iterate this array and add any button as a subview in your main view.

You need a for loop. For example:
float buttonWidth=50;
float margin=5;
for (int index=0; index<numberOfButtonsToBeInitialize;index++)
{
UIButton* button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
NSString* buttonTitle=[mutablearr objectAtIndex:index];
[button setTitle:buttonTitle forState:UIControlStateNormal];
[button setFrame:CGRectMake(0+(buttonWidth+margin)*index, 0, buttonWidth, 30)];
[button setTag:100+index];
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
In this case we layout buttons in a row(horizontally). Adjust to your own preferences

Related

How to save a reference to a control added programmatically?

I added 3 buttons programmatically to my view, then I added the buttons to an array so that I can access them at a later time:
for (i = 0; i < 3; i++)
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[view addSubview:button];
[_buttons addObject:button];
}
If I reference the button in my array and change the image of the button, it does not change the button on screen.
UIButton* button = [_buttons objectAtIndex: 0];
[button setImage:thumb forState:UIControlStateNormal];
I've found a way to change the image of the button by looping through all the subviews in my view, but is there a better way?
for (UIView* subView in ((UIView*)[self.view.subviews objectAtIndex:0]).subviews){
if ([subView isKindOfClass:[UIButton class]]){
UIButton *button = (UIButton*)subView;
if (button.tag == self.selected){
[button setImage:thumb forState:UIControlStateNormal];
}
}
}
A common reason for this is that your array has not been initialized. When this happens, Objective C does not complain or throw excetions: instead, it behaves as if the calls to add elements never happened. It also returns nil when you try getting items back.
Add this line to your viewDidLoad method:
_buttons = [NSMutableArray array];
This should solve the problem.
Possible this could help on a click event:
-(void)clickEvent:(id)sender
{
[sender setImage:thumb forState:UIControlStateNormal];
}
If this is how you are picking up the event.
When you do addSubview, view retains subview you are adding. Also addObject retains it. Hence both are different ojbects. Changing properties of object in array will not affect object retained by view.
You can avoid loop by using tags. While adding buttons on view set unique tags to them. And when you want to access them, get it using tag directly.
//set tags for buttons
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setTag:999];
[view addSubview:button];
//access using tag
UIButton *button = (UIButton*)[view viewWithTag:999];
[button setImage:thumb forState:UIControlStateNormal];
Add a tag to the button after creating it. And later use that tag to get that button.
for (i = 0; i < 3; i++)
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.tag = i+1;
[view addSubview:button];
[_buttons addObject:button];
}
Then you can access it like:
UIButton *button1 = (UIButton *)[self.view viewWithTag:1];
UIButton *button2 = (UIButton *)[self.view viewWithTag:2];
UIButton *button3 = (UIButton *)[self.view viewWithTag:3];
While adding UIControl programatically to use reference later add tag to it which should be different like:
yourBtn.tag = 111;
Now get reference of UIButton like this:
UIButton *button = (UIButton*)[yourViewWhereYouAdded viewWithTag:111];

Create toolbar for quiz app

This is related to a question i posted earlier.I am still stuck on it.Heres a description.I am creating a quiz app.It has a toolbar whose buttons are to be created dynamicaly each time the user clicks a button.I did it using a method which adds three buttons into an arrray, then uses a for loop to check the number of choices the question has and then create and add a button to the array for each choice.Later i use
[toolbar setitems:tempArray];
to add the buttons
But while doing this i am running into memory leaks.The app crashes after 200 questions.I found using instruments that the leaks were in button creation area.But after doing many experiments im at a loss about what to do.
I also have another question
Is there a way to find out the retain count of objects created by built in methods in iphone sdk.Specificaly,
1)Does NSMutableArray's addobject method increase the retain count of the added object
2)Is [[toolbar items] release] likely to cause trouble if i am intending to release the customBarButtonItem objects stored in it?
because wile playing with these options , the app either crashes immediately or the changes have no effect on the reported leaks
heres the code.Its got a lot of comment lines which are options i tried
- (void)CreateButtons{
UIToolbar *tempToolBar=[[UIToolbar alloc] ]
numberOfChoices=0;//set number of choice buttons at present to 0
NSMutableArray *tempItems=[[NSMutableArray alloc] init];//Array for holding the buttons
Question *question=[currentQuestion question];
NSString *answer=[question answerOptions];
int numericAnswer=0;
numericAnswer=[answer characterAtIndex:0];
//see if its a number or a character
if (numericAnswer > 96) { // its a character
int choice;
for (choice=97; choice <=numericAnswer ; choice ++) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setBackgroundImage:[UIImage imageNamed:#"gembtnblu.png"] forState:UIControlStateNormal];
button.frame = CGRectMake(0, 0, TOOLBAR_BUTTON_WIDTH , TOOLBAR_BUTTON_HEIGHT);
[button setTitle:[NSString stringWithFormat:#"%c",(char)choice] forState:UIControlStateNormal];
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[button addTarget:self action:#selector(ChoiceButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
[button setTag:choice];
UIBarButtonItem *customBarItem = [[UIBarButtonItem alloc] initWithCustomView:button];
if (isReviewing == TRUE) {
customBarItem.customView.userInteractionEnabled=FALSE;
}
//Add button to the array
[tempItems addObject:customBarItem];
//release buttons
[customBarItem release];
numberOfChoices++;
}
}
else {
int choice;
for (choice=49; choice<=numericAnswer; choice ++) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setBackgroundImage:[UIImage imageNamed:#"gembtnblu.png"] forState:UIControlStateNormal];
button.frame = CGRectMake(0, 0, TOOLBAR_BUTTON_WIDTH , TOOLBAR_BUTTON_HEIGHT);
[button setTitle:[NSString stringWithFormat:#"%c",choice] forState:UIControlStateNormal];
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[button addTarget:self action:#selector(ChoiceButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
[button setTag:choice];
UIBarButtonItem *customBarItem = [[UIBarButtonItem alloc] initWithCustomView:button];
//Add button to the array
[tempItems addObject:customBarItem];
if (isReviewing == TRUE) {
customBarItem.customView.userInteractionEnabled=FALSE;
}
//release buttons
[customBarItem release];
numberOfChoices++;
}
}
//load the image
UIButton *previousButton = [UIButton buttonWithType:UIButtonTypeCustom];
[previousButton setBackgroundImage:[UIImage imageNamed:#"prev.png"] forState:UIControlStateNormal];
[previousButton addTarget:self action:#selector(PreviousClicked:) forControlEvents:UIControlEventTouchUpInside];
previousButton.frame = CGRectMake(0, 0, TOOLBAR_BUTTON_WIDTH , TOOLBAR_BUTTON_HEIGHT);
UIBarButtonItem *customBarItem6 = [[UIBarButtonItem alloc] initWithCustomView:previousButton];
//[previousButton release];
self.prevButton=customBarItem6;
UIButton *nextButton= [UIButton buttonWithType:UIButtonTypeCustom];
[nextButton setBackgroundImage:[UIImage imageNamed:#"nex.png"] forState:UIControlStateNormal];
[nextButton addTarget:self action:#selector(nextClicked:) forControlEvents:UIControlEventTouchUpInside];
nextButton.frame = CGRectMake(0, 0, TOOLBAR_BUTTON_WIDTH, TOOLBAR_BUTTON_HEIGHT);
UIBarButtonItem *customBarItem7 = [[UIBarButtonItem alloc] initWithCustomView:nextButton];
//[nextButton release];
//Use this to put space in between your toolbox buttons
UIBarButtonItem *flexItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[tempItems addObject:flexItem];
[tempItems addObject:customBarItem6];
[tempItems addObject:customBarItem7];
//release buttons
[customBarItem6 release];
[customBarItem7 release];
[flexItem release];
//NSArray *items=[[NSArray alloc] initWithArray:(NSArray *)tempItems];
//[tempItems release];
//add array of buttons to toolbar
//if([[toolbar items] count]>0)
// {
// [[toolbar items] release];
// }
[toolbar setItems:tempItems animated:YES];
//[items release];
//[self.view addSubview:toolbar];
if(isReviewing == FALSE && isPractice == FALSE) {
prevButton.enabled=FALSE;
}
//[toolbar bringSubviewToFront:customBarItem6.customView];
}
toolbar is created via ib
Yeah its a lot of code but it just creates buttons based on number of choices for a question.The two for loops are similar exept one puts a,b,c,d on the buttons while the other one puts 1,2,3,4.....In addition three buttons are created.One for next, previous and a flex item .This method is is called each time the user clicks teh next button.
I can see a few things which are not very efficient memory-wise:
You use lots of convenience initializers: buttonWithType and 'imageNamed`. These will autorelease themselves at some point in the future but not within your method.
The item tempToolbar is allocated but never released. This will leak.
Your mutable array tempItems also does not appear to be released: this will kill you completely since all your buttons are added to it...
Based on this I would suggest:
Use of alloc/init methods instead of convenience constructors
Alternatively: create an NSAutoReleasePool at the start of your method and drain it at the end: this will release all autoreleased entities.
Good luck
Difficult to follow all that code, but an easy part-answer to 1) is that, yes, [NSMutableArray addObject:] increase retain +1.

Can I add OBject of button to NSMutableArray?

I am trying to create number of buttons on view programatically and for that I need array, so can I add button object in NSMutableArray?
Yes you can do that see the following code
// Create buttons for the sliding menu. For simplicity I create 5 standard buttons.
NSMutableArray *buttonArray = [[NSMutableArray alloc] init];
for(NSInteger i = 0; i < [self.slideMenuArray count]; i++)
{
// Rounded rect is nice
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
NSString *title=[slideMenuArray objectAtIndex:i];
[btn setFrame:CGRectMake(0.0f, 4.0f, 90.0f, 20.0f)];
[btn setTitle:[NSString stringWithString:title] forState:UIControlStateNormal];
[btn setBackgroundColor:[UIColor clearColor]];
[btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[[btn titleLabel] setFont:[UIFont systemFontOfSize:12]];
[btn addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
UIImage *backgroundView;
if(i==0)
backgroundView= [UIImage imageNamed:#"btnclk.png"];
else
backgroundView= [UIImage imageNamed:#"btn.png"];
[btn setBackgroundImage:backgroundView forState:UIControlStateNormal];
[buttonArray addObject:btn];
}
You can retrieve the added button objects like this-
for(int i = 0; i < [buttonArray count]; i++)
{
UIButton *btn = [buttonArray objectAtIndex:i];
// Move the buttons position in the x-demension (horizontal).
CGRect btnRect = btn.frame;
btnRect.origin.x = totalButtonWidth;
[btn setFrame:btnRect];
}
sure you can, and remember that when you do, every button or other object will be retained bu the array and released when you remove it from the array...
Yes, NSMutableArray can hold any objects

how to add a ui button that calls a number from an array and displays the phone number as the button title

anotherViewController.myLabel = [NSString stringWithFormat:#"Telephone %#",
anotherViewController.title];
this is the declaration for a previus label however im not sure how to do this for a button...
the data array is located made in this format
phoneNumbers = [[NSArray alloc] initWithObjects:#"6940313388", #"4045434218", nil ];
self.phoneNumbers =phoneNumbers;
and then the labels are simply added by
theLabel.text = myLabel;
where mylabel is an NSString
please help ive been trying to solve this for a very long time ...
this is the code i use to make buttons. then you add the button to a view !
edit: you would change the setTitle: part of this to whatever string you wanted the button to display as its title.
//create the button
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
//sets its size
[button setFrame:CGRectMake(10, 10, 300, 50)];
//set title, font size and font color
[button setTitle:#"Sign Up" forState:UIControlStateNormal];
[button setFont:[button.font fontWithSize:22]];
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:#"green_btn_bg.png"] forState:UIControlStateNormal];
//set action of the button
[button addTarget:self action:#selector(signUp:)
forControlEvents:UIControlEventTouchUpInside];

Add a multiple buttons to a view programmatically, call the same method, determine which button it was

I want to programmatically add multiple UIButtons to a view - the number of buttons is unknown at compile time.
I can make one or more UIButton's like so (in a loop, but shorted for simplicity):
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self
action:#selector(buttonClicked:)
forControlEvents:UIControlEventTouchDown];
[button setTitle:#"Button x" forState:UIControlStateNormal];
button.frame = CGRectMake(100.0, 100.0, 120.0, 50.0);
[view addSubview:button];
Copied/Edited from this link:
How do I create a basic UIButton programmatically?
But how do I determine in buttonClicked: which button was clicked? I'd like to pass tag data if possible to identify the button.
You could either keep a reference to the actual button object somewhere that mattered (like an array) or set the button's tag to something useful (like an offset in some other data array). For example (using the tag, since this is generally must useful):
for( int i = 0; i < 5; i++ ) {
UIButton* aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[aButton setTag:i];
[aButton addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[aView addSubview:aButton];
}
// then ...
- (void)buttonClicked:(UIButton*)button
{
NSLog(#"Button %ld clicked.", (long int)[button tag]);
}
You can assign a tag to the button.
button.tag = i;
Then in -buttonClicked:, check the tag of the sender:
-(void)buttonClicked:(UIButton*)sender {
int tag = sender.tag;
...
}
I think this would be the best answer:-
http://conecode.com/news/2012/05/ios-how-to-create-a-grid-of-uibuttons/
For that give different tag to each button & use code like this:
[btn1 addTarget:self action:#selector(pressbtn:) forControlEvents:UIControlEventTouchUpInside];
[btn2 addTarget:self action:#selector(pressbtn:) forControlEvents:UIControlEventTouchUpInside];
& in method
-(void)pressbtn:(id)sender {
UIButton *button=sender;
if (button.tag==1)
{
NSLog(#"Press button 1");
}
if (button.tag==2)
{
NSLog(#"Press button 2");
}
and so on to check which button is called
If you want to add buttons at run time then there will be 10 20 50 or more than that. Then you should to use ui scroll view in this condition.
When the buttons will be generate then your scroll view size should be increased accordingly.
And you can write the code like this
scrollview = [[UIScrollView alloc] init];
scrollview.contentSize = CGSizeMake(INVOICE_ADDITEM_SCROLLVIEW_CONTENT_WIDTH, INVOICE_ADDITEM_SCROLLVIEW_CONTENT_HEIGHT);
scrollview.frame = CGRectMake(0,50, SCROLLVIEW_WIDTH, SCROLLVIEW_HEIGHT);
// scrollview.backgroundColor = [UIColor whiteColor];
scrollview.scrollsToTop = NO;
scrollview.delegate = self;
[self.view addSubview:scrollview];
for (int pos = 0; pos < 2; pos++) {
UIButton *but = [UIButton buttonWithType:UIButtonTypeCustom];
[but setImage:[UIImage imageNamed:#"checkbox.png"] forState:UIControlStateNormal];
[but setImage:[UIImage imageNamed:#"checkbox_active.png"] forState:UIControlStateSelected];
[but setFrame:CGRectMake(TXT_FLD_X_CORD+90, 295, 20, 20)];
// [but setCenter:CGPointMake( 50, i*40+20 )];
but.tag = pos;
/*if(pos==0)
{
[but setImage:[UIImage imageNamed:#"checkbox_active.png"] forState:UIControlStateNormal];
// [but setImage:[UIImage imageNamed:#"checkbox_active.png"] forState:UIControlStateSelected];
}*/
[but setCenter:CGPointMake(pos*90+125 ,310)];
[but addTarget:self action:#selector(checkboxButton:) forControlEvents:UIControlEventTouchUpInside];
[scrollview addSubview:but];
}
UIButton has a tag property. Use that and in your buttonClicked method, you can check the button that was clicked based on it's tag. Might want to keep constants around for what button is what.
For each of your buttons set an appropriate tag, and then refer to the tag in your action. i.e.
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
...
button.tag = 1
[view addSubview:button];
You can easily set the tag based on the index of your iteration, if you're creating buttons in a loop. And then in your action:
- (void)aButtonWasTapped:(UIButton *)source {
if( source.tag == 1 ) {
// etc
}
}
Somebody might have this problem:
Jason Coco's answer worked fine for me, until I wanted to use the tag to access properties from an NSArray that was defined as a property.
Turns out the property had to be defined as "retain" instead of "weak".
The Swift version (with Labels):
for index in 1...5 {
var label = UILabel()
label.tag = index
labelsDictionary["Label\(index)"] = label
self.addSubview(label)
}
Call using using self.viewWithTag(i) as UILabel:
(cell.viewWithTag(5) as UILabel).text