I have a button named by
UIButton *button1;
how can i save 'button1' in string? or am i able to save it or not?
You can save its' address in memory only: NSString *but1=[NSString stringWithFormat:#"%#",&button1];, but if you need to get unique indicator of your buttons, you can use its' tags: button1.tag
Or you can create NSMutableDictionary and add buttons for keys, which equals their names.
You can create a macro like this:
#define getVariableName(var) [NSString stringWithFormat:#"%s", #var]
And use it:
NSLOG(#"My variable name is %#", variableName(self.button1));
You'll see
My variable name is button1
No you can't do this, as UIButton is an object and you are declaring UIButton as button1. This will remain static as it holds the reference in memory.
NSString is something that you can chage any time, but for Object and varible declaration you can't change it.
you get button title in string but not saved button outlet in string you save button outlet in id using this you save button title
NSString *btn = Mybutton.titleLabel.text;
for save button outlet
Iboutlet Uibutton *myButton;
id *myBtn=myButton;
Check this
import
#import "objc/runtime.h"
-(IBAction)btnItemListClicked:(id)sender
{
UIButton *btn=sender;
NSString *name = nil;
uint32_t ivarCount;
Ivar *ivars = class_copyIvarList([self class], &ivarCount);
if(ivars)
{
for(uint32_t i=0; i<ivarCount; i++)
{
Ivar ivar = ivars[i];
id pointer = object_getIvar(self, ivar);
if(pointer == sender)
{
name = [NSString stringWithUTF8String:ivar_getName(ivar)];
break;
}
}
free(ivars);
}
NSLog(#"%#", name);
}
Output is:
Printing description of name:
btnconferenceCall
Check this sample demo
ButtonDemo
Related
I am working with a UILabel and assign some string value on it, now I want to update its value every time when I click on UIButton. See me IBAction code.
- (IBAction)IncreasePack:(id)sender {
int increseprice = [value intValue];
int updateprice = [price intValue];
NSString *newprice= [NSString stringWithFormat:#"%d", increseprice+updateprice];
_TotalPrice.text = newprice;
NSLog(#"newprice %#",newprice);
}
When I click button the first time, my logic executes fine. But when I tap again the code is not executed but its print every time on every click.
Try this:
in .h file
#property (strong, nonatomic) int labelValue;
in .m file
- (void)viewWillAppear{
self.labelValue = 0;
}
- (IBAction)buttonClicked:(UIButton *)sender{
self.labelValue++;
[self.label setText:[NSString stringWithFormat:#"%d", self.labelValue]];
}
Your code does not make sense. Your IBAction calculates newprice from increseprice+updateprice. If increseprice and updateprice don't change, the sum of those values won't change either.
You need an instance variable that hold the current value, and when the user clicks your button you need to add the increase value to that previous value and update the total
Instead you always say
newprice = increseprice + updateprice
Nowhere do you save the new total. Click the button again and neither increseprice update price will have changed, so newprice will still be the same value.
So we have a plist which features an array of dictionaries. The Array is allCategories and it currently features two dictionaries acting as questions. Each dictionary has a set of strings. The goal is so that when you press the button it will check whether it is correct and if so increment currentQuestion and setTitle and picture for the new dictionary in allCategory array. This, however doesn't work and we don't know how to fix it. So far it recognizes that it is the correct question and that it should change it, however nothing is displayed. If we make currentQuestion = 1 and remove the currentQuestion++ and we click the button it works perfectly. We want it to increment based on whether it is correct though.
- (IBAction)showPic
{
NSDictionary *picturesDictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Property List" ofType:#"plist"]]; //sets the proper plist file
allCategory = [picturesDictionary objectForKey:#"AllCategory"]; //Sets the array allCategory
currentQuestion++; //There are currently 2 dictionaries acting as the questions.
NSDictionary *QuestionNumber = [allCategory objectAtIndex:currentQuestion]; answerKey = [QuestionNumber objectForKey:#"correctAnswer"];
correctAnswer = [QuestionNumber objectForKey:answerKey]; //the two lines above determine what the correct answer is based on the plist.
if([self.buttonOutlet.currentTitle isEqualToString:correctAnswer]) //this is where the comparison is made.
{
NSLog(#"currentQuestion:%d", currentQuestion);
//the button titles should change to the next dictionary in allCategory, however it wont change.
self.Label.text = #"This is working";
}
else if(currentQuestion != 0){
[self.buttonOutlet setTitle: [QuestionNumber objectForKey:#"A"] forState:UIControlStateNormal];
[self.buttonTwo setTitle: [QuestionNumber objectForKey:#"B"] forState:UIControlStateNormal];
[self.buttonThree setTitle: [QuestionNumber objectForKey:#"C"] forState:UIControlStateNormal];
[self.buttonFour setTitle: [QuestionNumber objectForKey:#"D"] forState:UIControlStateNormal];
UIImage *img = [UIImage imageNamed: [QuestionNumber objectForKey:#"fileName"]];
[imageHolder setImage:img];
self.Label.text = #"This is correct";
}
else {
self.Label.text = #"This is not correct";
}
}
this is the plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AllCategory</key>
<array>
<dict>
<key>fileName</key>
<string>gta.jpg</string>
<key>A</key>
<string>gta</string>
<key>B</key>
<string>COD</string>
<key>C</key>
<string>LOL</string>
<key>D</key>
<string>Watchdogs</string>
<key>correctAnswer</key>
<string>A</string>
</dict>
<dict>
<key>fileName</key>
<string>LOL.jpg</string>
<key>A</key>
<string>Watchdogs</string>
<key>B</key>
<string>La Noir</string>
<key>C</key>
<string>Dota 2</string>
<key>D</key>
<string>fifa</string>
<key>correctAnswer</key>
<string>D</string>
</dict>
</array>
</dict>
</plist>
You need to remove
int currentQuestion = 0;
and set it somewhere outside of the IBAction otherwise each time you hit the button it will reset currentQuestion to 0.
Why do you create a key for the answer
answerKey = [QuestionNumber objectForKey:#"correctAnswer"];
correctAnswer = [QuestionNumber objectForKey:answerKey];
you should just be able to access it direcltly
correctAnswer = [QuestionNumber objectForKey:#"correctAnswer"];
and get rid of the answerKey
This really comes down to a matter of variable scope. A property defined in the .h file is globally visible to all methods in your class, and will be visible to any external classes that subclass or use your class. Those are public properties that are visible so that others who may re-use your method in the future can pass the information into your method without necessarily having to know what the internals do. You can also have an interface section at the top of your .m file. This is for methods that like the .h file have global scope within the class, but they are not visible to other classes using your class. Both of these types of properties are accessed in your methods by using the self. prefix. A variable defined inside of a method is only visible inside that method and does not require the self. prefix. Local variables have a lifespan of the method they are in. Each time you re-enter the method a new instance of that variable is created.
In your case, currentQuestion is defined as a local variable inside your method. Each time you come into it, you create the variable and initialize it to zero. By doing what meda said and moving it outside of your method, it is a global property and can be seen by all methods inside your class. When you initialize it in viewDidLoad or another method that initializes early in the viewcontrollers life, you set it to zero once and then you increment it like you are doing in the if statement of your method.
Moving it to the bottom of the if statement won't really help any since you don't seem to reference it anywhere in the if statement (unless I missed one), but moving it to the bottom does eliminate any confusion around which things are being displayed inside the if statement. So it's good from that perspective.
Try this:
#import "exViewController.h"
#interface exViewController ()
#property (nonatomic) NSInteger currentQuestion;
#property (weak, nonatomic) IBOutlet UILabel *Label;
#property (weak, nonatomic) IBOutlet UIImageView *imageHolder;
#property (weak, nonatomic) IBOutlet UIButton *buttonOutlet;
#property (weak, nonatomic) IBOutlet UIButton *buttonTwo;
#property (weak, nonatomic) IBOutlet UIButton *buttonThree;
#property (weak, nonatomic) IBOutlet UIButton *buttonFour;
#property (nonatomic,strong) NSDictionary *picturesDictionary;
#property (nonatomic,strong) NSArray *allCategory;
#property (nonatomic,strong) NSDictionary *QuestionNumber;
#end
#implementation exViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// we have to initialize the screen with the first question.
// There isn't any reason to re-initialize these every time you pick an answer do
// do it up here in viewDidLoad
self.picturesDictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"PropertyList" ofType:#"plist"]]; //sets the proper plist file
self.allCategory = [self.picturesDictionary objectForKey:#"AllCategory"]; //Sets the array allCategory
// Initialize currentQuestion to 0
self.currentQuestion=0;
// I put the statements to display the question into another method so they wouldn't
// have to be put in the code multiple times. Makes it easier to maintain.
[self displayQuestion:self.currentQuestion];
}
// display question takes one arguement, the value for currentQuestion so it's going
// to display the question associated with whatever index is.
- (void) displayQuestion:(NSInteger) index
{
// get questionNumber like you did before, but using index which we passed into this method.
self.QuestionNumber = [self.allCategory objectAtIndex:index];
self.picturesDictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"PropertyList" ofType:#"plist"]]; //sets the proper plist file
self.allCategory = [self.picturesDictionary objectForKey:#"AllCategory"]; //Sets the array allCategory
[self.buttonOutlet setTitle: [self.QuestionNumber objectForKey:#"A"] forState:UIControlStateNormal];
[self.buttonTwo setTitle: [self.QuestionNumber objectForKey:#"B"] forState:UIControlStateNormal];
[self.buttonThree setTitle: [self.QuestionNumber objectForKey:#"C"] forState:UIControlStateNormal];
[self.buttonFour setTitle: [self.QuestionNumber objectForKey:#"D"] forState:UIControlStateNormal];
UIImage *img = [UIImage imageNamed: [self.QuestionNumber objectForKey:#"fileName"]];
[self.imageHolder setImage:img];
}
//This was your old showPic method. I added the sender parameter being sent to it.
// it points to the button that was clicked.
- (IBAction)showPicture:(UIButton *)sender
{
NSDictionary *QuestionNumber = [self.allCategory objectAtIndex:self.currentQuestion];
NSString *answerKey = [QuestionNumber objectForKey:#"correctAnswer"];
NSString *correctAnswer = [QuestionNumber objectForKey:answerKey]; //the two lines above determine what the correct answer is based on the plist.
NSLog(#"answerkey=%#",answerKey);
NSLog(#"Correctanswer=%#",correctAnswer);
NSLog(#"sender=%#",sender.description);
//remember we are now passing in the address of the button that we clicked so we
//can just checking sender(the button).titleLabel.text and see if it's equalto the correct answer.
if(![sender.titleLabel.text isEqualToString:correctAnswer])
{
// wrong answer
NSLog(#"currentQuestion:%d", self.currentQuestion);
self.Label.text = #"Wrong Answer";
}
else {
// right answer go to next question
self.currentQuestion++;
// make sure we don't go outside our bounds past the last question.
if(self.currentQuestion<[self.allCategory count]) {
self.Label.text = #"This is correct!! Next question";
// call the method to display the question using the incremented currentQuestion.
[self displayQuestion:self.currentQuestion];
} else {
self.Label.text = #"Correct answer end of test";
}
}
}
#end
This is the code I am using to dynamically change text in my UITextView based on which item is selected in my NSArray.
NSMutableString *flavorsText = [NSMutableString string];
for (NSString* preworkout in self.preWorkout.flavors) {
[flavorsText appendFormat:#"%#\n", preworkout];
}
self.flavorsTextView.text = flavorsText;
I am curious as to how I can change the link behind a single button based on the link that is typed into the NSArray. I want it to have the same functionality as this code above basically.
You need to store the URL somewhere. Add a property to your class:
#property (nonatomic, strong) NSURL *storeURL;
The button code should look something like this:
- (IBAction)buyNow:(id)sender
{
[someWebView loadRequest:[NSURLRequest requestWithURL:self.storeURL]];
}
When the user changes the selection, update the storeURL property with the new URL.
Basically you have an array, someArrayOfLinks, that contains NSString url strings, correct?
So, as you know arrays are based on indexes, so someArrayOfLinks[9] gives you the 10th item in the array (starts at 0). All UIView objects and their subclasses feature a tag property that holds an integer. So, what I'd do is something like this:
Wherever you are setting the flavors:
self.buyNowButton.tag = someInteger;
Then, when they tap the button
- (IBAction)didSelectBuyNowButton:(UIButton *)sender {
NSString *urlPath = someArrayOfLinks[sender.tag];
NSURL *url = [NSURL URLWithString:urlPath];
[[UIApplication sharedApplication] openUrl:url];
}
I am new to iOS app development. currently I am working on a very simple application that displays two words on the screen and the user selects one and the app just outputs you have selected x.
I have created two plists and i have loaded them onto an array and randomised them in the array. On my view I have two buttons that i want the words to display on them. However, I am having two problems..
1 . I want the label on the buttons to change when the app starts. So the user doesn't have to tap on the button or anything.
2. I want one random word from array_1 (loaded from a plist) to appear on a random button. either button_1 or button_2 and the same for list array_2.
Here is what i have done so far. (with some help from forums (: )
- (IBAction)buttonpressed:(id)sender {
// Load contents of plist onto array
NSString *path = [[NSBundle mainBundle] pathForResource:#"wordsOne" ofType:#"plist"];
NSMutableArray *words = [NSMutableArray arrayWithContentsOfFile:path];
//shuffle them using Fisher–Yates shuffle algorithm
for (int i = words.count-1; i>=0; i--) {
int r = arc4random_uniform(words.count);
[words exchangeObjectAtIndex:i withObjectAtIndex:r];
}
// assign word to the button
for (int j =0; j<_WordButton.count; j++) {
UIButton *button = [_WordButton objectAtIndex:j];
button.titleLabel.text = [words objectAtIndex:j];
}
}
There are obviously flaws in the above code, for example it uses only one plist and it doesn't display words on both buttons randomly.
You can set UIButton Title by using following code:
[button setTitle:titleString forState:UIControlStateNormal];
To achieve what you are looking to do you have to create an IBOutlet to the buttons on your .xib file. You can do this by using an easy Xcode shortcut that will create the IBOutlet code and make the connection from the .xib file to the code simultaneously for you:
Open up the .xib file in Xcode which will show a graphic file using Interface Builder.
In the toolbar at the top-right of Xcode is an icon that allows you to toggle through different modes, select the 'Assistant Editor'. The Interface Builder will slide over to share the window with a code file, this should automatically select your ViewController.h
The toolbar should look like this:
Insert some curly-brace in your code like so:
`
#interface CustomViewController : UIViewController {
// This is where you will control-drag to from the Interface Builder to have it create an IBOutlet to the button for you
}
// Your already set-up IBAction Method
- (IBAction)buttonpressed:(id)sender
#end
`
Control-drag from the button you wish your label to change to the area between the curly-braces in the .h file:
A new dialog box will appear. Make sure that the settings are as follow:
a. Connection = IBOutlet
b. Name = (Whatever you want to call the button, you've used '_wordButton')
c. Type = UIButton
d. Storage = WEAK
Now in your action method - (IBAction)buttonpressed:(id)sender and in your application:didFinishLaunchingWithOptions (to automatically load a word into the label when the application is launched) you can set the button title with the following:
`
// Create a string from the word that you pull out of the plist file
NSString *labelWord = ???;
// Set the label of the button
[_wordLabel setTitle:word forState:UIControlStateNormal];
`
Do it like this:
-(void)viewDidLoad{
[self setnewtitle];
}
-(void)setnewtitle{
NSString *pathone = [[NSBundle mainBundle] pathForResource:#"wordsOne" ofType:#"plist"];
NSMutableArray *wordsOne = [NSMutableArray arrayWithContentsOfFile:pathone];
NSString *pathtwo = [[NSBundle mainBundle] pathForResource:#"wordsOne" ofType:#"plist"];
NSMutableArray *wordsTwo = [NSMutableArray arrayWithContentsOfFile:pathtwo];
int words = "the number of objects(words) in your plist";
int randombutton = arc4random() % 2;
int randomplist = arc4random() % 2;
int randomWord = arc4random() % words;
if (randombutton==0){
if (randomplist==0){
[[_WordButton objectatIndex:randombutton] setTitle:[wordsOne objectatIndex:randomWord]];
} else {
[[_WordButton objectatIndex:randombutton] setTitle:[wordsTwo objectatIndex:randomWord]];
}
}else {
if (randomplist==0){
[[_WordButton objectatIndex:randombutton] setTitle:[wordsOne objectatIndex:randomWord]];
} else {
[[_WordButton objectatIndex:randombutton] setTitle:[wordsTwo objectatIndex:randomWord]];
}
}
}
Please make sure that the in the Array contained Buttons are initialized and allocated, also
if you have any questions please be free to ask
I'm new in Objective-c and Xcode. I'm trying to get large numbers from certain buttons but all I got is only one number. I'm using button tag for that.
For instance: if I want to add two numbers 2+3, it works well. but when I want to add 230+32, it doesn't.
Interface :
- (IBAction)getnumber:(id)sender;
#property (strong, nonatomic) IBOutlet UILabel *Result;
int number;
Implementation part:
-(IBAction)getnumber:(id)sender {
number = [sender tag];
Result.text = [NSString stringWithFormat:#"%i", number];
}
Is there any way to get a large number from button's tag, if I tapped more than one button?
Thank you in advance .
Your problem comes from how you are defining your variables. If I understand your setup right, you have something like a calculator interface, and you are only setting button's tags to single digit numbers like 1, 2, 3, ... to indicate the next digit to display?
In that case your line number = [sender tag] will set a global variable to that button's number (remember when your CS prof told you never to use globals? Here's a reason why!) Since you just overwrote number with this button's tag when you go to set your result string in the next line, number only holds the value of the last button pressed. Instead you should do something like this.
#interface MyClass : UIViewController
#property (nonatomic, strong) IBOutlet UITextView * resultLabel;
- (IBAction)getNumber:(id)sender;
#end
and
- (IBAction)getNumber:(id)sender;
{
self.resultLabel.text = [NSString stringWithFormat:#"%#%d", self.resultLabel.text, [sender tag]];
}
In this way, every time getNumber: is called, it takes whatever text the label is currently displaying and append's this button's value. As a side note, its conventional to start Objective-C property names with a lowercase letter.
I think you have to attach a variable type to number. It should be -
- (IBAction)getnumber:(id)sender
{
NSInteger number = [sender tag];
Result.text = [NSString stringWithFormat:#"%i", number];
}
I
You need to change your logic.
number = 0;
if button with number is clicked
number = number * 10 + button.tag;
else
if operation (not =) is pressed
store the number and operator
if = operatior is clicked
perform the operation on stored number and recently entered number.