Why is my button clicked event being called 4 times? - iphone

Probably a noob question, but I'm trying to write a simple iPhone app that increments a label by the number of times a button is clicked. I have the following code:
#import "Controller.h"
int *i = 0;
#implementation Controller
- (IBAction)buttonClicked:(id)sender {
NSString *numTimesClicked = [NSString stringWithFormat:#"%d",i++ ];
myLabel.text = numTimesClicked;
}
#end
When I click the button, the label updates in multiples of 4 (4,8,12,16, etc). What might I be doing wrong here?

Look at the definition of i:
int *i = 0;
i isn't an integer — it's a pointer to an integer. The size of an int is 4 bytes on your architecture, so the pointer increments by 4 (which would be the address of the next int in an array of ints). You want to declare it as just int i = 0.

Related

Display a number in a label but have it count up the number

I have a UILabel in my class and I would like the view to display the number but to count up to the number. For example, If the number was 368, it would climb quickly to the 250-300's then start to slow down as it gets to the number. Now this number will not always be 368, the number varies. It could be 6 or 129 or 1023 so it can't be a set-in-stone number. I obviously know how to create the UILabel as I already have it being used in my app, I just need help with counting upwards to it.
I have a "Player view", blah blah blah they get a score and it is passed to another view "Gameover view" and the score is display in a the UILabel.
Here is the code for the "Player view" to pass the data:
//finalScore is a int and so is currentScore
second.finalScore = self.currentScore;
Here is the code for the "Gameover view" to pass the data:
- (void)viewWillAppear:(BOOL)animated {
// scoreLabel is the IBOutlet to the UILabel in IB for displaying the score.
self.currentIndex++;
if(self.currentIndex == [self.numbersArray count]) self.currentIndex = 0;
self->scoreLabel.text = [NSString stringWithFormat:#"%d",self->finalScore];
}
Thanks in advance!
I figured it out myself. I found this control and it works just as I need it to! Click Here
You can update the UILabel object in a loop, using the Timer. As time progresses at a certain interval, "slow it down" by adding on the difference in time. Sample code for updating a UI object via Timer is a common bit of code on the Internet, as it's the way you code progress bars.
how to use the progress bar in the iphone app
Just call this method every certain interval (ex every 0.1 seconds), using a NSTimer
It will increment the value up to the target number.
-(void)countUp:(id)sender {
int targetNumber = yourNumber;
int currentNumber = [[myLabel text] intValue];
// Calculate the increment for this time. Mess with this for different speeds.
// Just multiply some of the numbers by some constants (ex. 2) until you
// achieve the desired effect.
double increment = (targetNumber - currentNumber) / targetNumber;
NSString *newValue = [NSString stringWithFormat:#"%f",currentNumber + increment];
[myLabel setText:newValue];
if ([newValue doubleValue] >= targetValue) {
[(NSTimer *)sender invalidate];
}
}
For the timer:
[NSTimer scheduledTimerWithInterval:0.1
target:self
selector:#selector(countUp:)
userInfo:nil
repeats:YES];
using literals it become quite easy to play
UILabel * label;
label.text = #(label.text.integerValue+1).stringValue;

(Obj-C) Is there any way to allocate all my NSDecimalNumbers at once for use in various parts of a calculator-style app?

I'm working with about 10 or so NSDecimalNumbers in my app, but I'm having trouble finding a way to just allocate them all at once for use by all the various buttons on the storyboard. The #interface of viewcontroller.h would've been the logical location, but it won't let me go past "NSDecimalNumber *one." What should I do?
Also, as I need the values in each object simply altered as I go, (as opposed to deleted and recreated), what should I do about memory release?
I'm still fairly new to programming, so try not to be overly technical. Thanks in advance!
#Kurt Revis
All right, let me try to give an example:
In viewcontroller.h, we have 1 outlet and 2 actions, connected to a label and 10 buttons. We also have the NSDecimalNumbers screen and digit.
#interface viewcontroller:UIViewController{
IBOutlet UILabel *CalculatorScreen;
NSDecimalNumber *screen;
NSDecimalNumber *digit;}
- (IBAction)DigitPressed:(id)sender;
- (IBAction)OperatorPressed:(id)sender;
When "DigitPressed" is hit, the NSDecimalNumber "screen" is calculated like so in viewcontroller.m:
- (IBAction)DigitPressed:(id)sender {
screen= [[screen decimalNumberByMultiplyingBy: ten] decimalNumberByAdding:digit];}
(where "ten" is also an NSDN.) But in order to do that (or so I thought), "screen" has to be allocated like so:
screen=[NSDecimalNumber alloc];
so now we get this:
- (IBAction)DigitPressed:(id)sender {
screen=[NSDecimalNumber alloc];
screen= [[screen decimalNumberByMultiplyingBy: ten] decimalNumberByAdding:digit];}
-- but then it's allocated to a new address with each hit. Similarly, if I try to use the number in my "OperatorPressed" section, it will have to be independently allocated.
Therefore, I need a way to allocate the memory once and then just use the number over and over in all methods of my .m file.
I'll go through and make this stuff work. Also, I'll change the case on some of your names to match typical Objective-C practice -- hope you don't mind.
#interface ViewController : UIViewController {
IBOutlet UILabel *calculatorScreen;
NSDecimalNumber *screen;
}
- (IBAction)digitPressed:(id)sender;
#end
You need to initialize screen to a reasonable starting value. Since your class is a view controller, a good place to do that is -viewDidLoad.
- (void)viewDidLoad
{
[super viewDidLoad]; // in case your superclass needs to do any work
screen = [NSDecimalNumber zero];
// also, make sure it shows up in the UI
calculatorScreen.text = [screen stringValue]; // Convert from NSDecimalNumber to NSString, and pushes it into the label
}
Next, the digit buttons. It's unclear whether you expected there to be one digitPressed: method that is called by all 10 digit buttons, or whether it was supposed to be for only one of the buttons. To start, it's easiest to make a separate action for each button.
Here's the method for the "1" button:
- (IBAction)digit1Pressed:(id)sender {
// Create intermediate values
NSDecimalNumber* one = [NSDecimalNumber decimalNumberWithMantissa:1 exponent:0 isNegative:NO]; // 1 * 10^0 = 1
NSDecimalNumber* ten = [NSDecimalNumber decimalNumberWithMantissa:1 exponent:1 isNegative:NO]; // 1 * 10^1 = 10
// Compute the new result
NSDecimalNumber* result = [[screen decimalNumberByMultiplyingBy:ten] decimalNumberByAdding:one];
// Put the result back in the screen
screen = result;
// and update the UI
calculatorScreen.text = [screen stringValue];
}
Similarly, the "2" button would be hooked up to this action:
- (IBAction)digit2Pressed:(id)sender {
NSDecimalNumber* two = [NSDecimalNumber decimalNumberWithMantissa:2 exponent:0 isNegative:NO]; // 1 * 10^0 = 1
NSDecimalNumber* ten = [NSDecimalNumber decimalNumberWithMantissa:1 exponent:1 isNegative:NO]; // 1 * 10^1 = 10
// take a shortcut and don't bother with the `result` variable
screen = [[screen decimalNumberByMultiplyingBy:ten] decimalNumberByAdding:two];
calculatorScreen.text = [screen stringValue];
}
And so on. Note that we didn't have to remember "one", "two", and "ten" in the view controller -- we can just create them when we need them, and let them get deallocated when we're done with them. (Yes it's slightly more inefficient, but these objects are tiny and lightweight; you could create thousands of them every second and nobody would notice.)
Your next question: isn't it stupid to have 10 separate "digit" actions? Yes. You could instead have one "digitPressed" action that looked at the sender, determined which button it was, and then did the right thing.
An easy way to tell which button is which: When you create the button, set its tag to be the same as its digit. You can set this via code, or in the interface builder. Then, the action method looks up the sender's tag.
- (IBAction)digitPressed:(id)sender {
NSDecimalNumber* digit = [NSDecimalNumber decimalNumberWithMantissa:[sender tag] exponent:0 isNegative:NO]; // digit * 10^0
NSDecimalNumber* ten = [NSDecimalNumber decimalNumberWithMantissa:1 exponent:1 isNegative:NO]; // 1 * 10^1 = 10
screen = [[screen decimalNumberByMultiplyingBy:ten] decimalNumberByAdding:digit];
calculatorScreen.text = [screen stringValue];
}

Appending UIButton with NSString

I have this code to show some text in a textview from SQLite DB..
NSMutableString *combined = [NSMutableString string];
for(NSUInteger idx = 0; idx < [delegate.allSelectedVerseEnglish count]; idx++) {
[combined appendFormat:#" %d %#", idx, [delegate.allSelectedVerseEnglish objectAtIndex:idx]];
}
self.multiPageView.text = combined;
self.multiPageView.font = [UIFont fontWithName:#"Georgia" size:self.fontSize];
delegate.allSelectedVerseEnglish is the NSArray
multiPageView is the UITextView
i put the above loop function to get the Numbers according to the text,for example 1 hello 2 iPhone 3 iPad 4 mac etc etc..i just want UIButton between the text instead of 1 2 3 4 ..for example i want unbutton hello unbutton iPhone etc etc.because i need to make some touch events from it.how to do this?
Thanks in advance.
If you want to place UIButtons between some text in textview, there is no other way but to place it as a separate view just above. So you'll need to add spaces beneath those buttons, the amount of those you should calculate yourself, based on the size of your buttons.
So, if you would like yo see something like this:
Press here [UIButton] or here [Another UIButton],
your text string should look like this
Press here or here ,
So when you add the buttons on those places, it would look just like you wish.
UPDATE
Seems like we need some more code here, so here it is:
First, you'll need to calculate the size of a letter. Let's assume that it is 10 pixels height and 8 pixels.No, let's just call that letterHeight and letterWidth.Let's also assume that you want 64x10 pixels buttons. So, we will need 64/8=8 +2 spaces to out behind that button(2 to make borders around that)
So, here we go
NSMutableString *combined = [NSMutableString string];
int letterHeight = 10;
int letterWidth = 8;
for(NSString *verse in delegate.allSelectedVerseEnglish) {
[combined appendFormat:#" %#",verse];//10 spaces there
//You have to experiment with this, but idea is that your x coordinate is just proportional to the length of the line you are inserting your button in, and y is proportional to number of lines
int xCoordinate = [combined length]*letterWidth%(int)(self.multiPageView.frame.size.width);
int yCoordinate = [combined length]*letterWidth/(int)(self.multiPageView.frame.size.width)*letterHeight;
UIButton *newButton = [[UIButton alloc]initWithFrame:CGRectMake(xCoordinate,yCoordinate,64,10)];
[self.multiPageView addSubview:newButton];
}
self.multiPageView.text = combined;

Method returns 0 instead of the number I assigned to the variable

I'm trying to get the basics of iOS programming down. I have an app that shows a random number when I click a button.. At least, that's what I wanted to make. However, it doesn't seem to be working out.
I have the following basic method which should set the text of myLabel to the return value of generateRandomNumber. However, it always returns 0. I think the syntax I'm using here is correct since it works for the commented parts:
-(IBAction)myBtnPressed:(UIButton *)sender
{
//[myLabel setText:#"test"];
//[myLabel setText:[NSString stringWithFormat:#"%g / 15", 3.14]];
[myLabel setText:[NSString stringWithFormat:#"%g / 15", [myModel generateRandomNumber]]];
}
The last line sets the label to display 0/15. However, in my model, I have the following code ('static' for now):
-(double)generateRandomNumber
{
randomNumber = 1.34;
return randomNumber;
}
It doesn't return the 1.34 and I don't understand why it doesn't. Can someone clear this up?
Update
This is the code for my viewcontroller.m file:
#import "myViewController.h"
#implementation myViewController
-(MyModel *)myModel
{
if (! myModel) {
myModel = [[MyModel alloc] init];
}
return myModel;
}
-(IBAction)myBtnPressed:(UIButton *)sender
{
[myLabel setText:[NSString stringWithFormat:#"%g / 15", [myModel generateRandomNumber]]];
}
#end
Also, in the end, I want to make generateRandomNumber return a random number between 0 and 15. How would I do this? Would a simple line like:
int x = arc4random() % 16;
work for this? Or do I have to seed it in some way so it doesn't always return the same values when I run the application?
Thanks in advance.
It doesn't return the 1.34 and I don't understand why it doesn't. Can someone clear this up?
Almost certainly, you haven't allocated and initialised the myModel object. You can send messages to nil without crashing but the return value will be 0.
arc4random() doesn't need a seed.
Edit
Your init code looks OK but you are not calling int, in your myBtnPressed: method, you need
[myLabel setText:[NSString stringWithFormat:#"%g / 15", [[self myModel] generateRandomNumber]]];
Are you instantiating an object of your model type? I'm asking because you say that you have declared the function in myModel.h (Could be a typo).
And yes - to get a random number between 0 and X:
int rand = arc4random() % X;
And you don't need to seed the generator.
To return a double between 0 and 15:
// define this somewhere
#define ARC4RANDOM_MAX 0x100000000
// and then use this
double val = floorf(((double)arc4random() / ARC4RANDOM_MAX) * 15.0f);
random-thoughts-rand-vs-arc4random.html for more.
Did you ever alloc/create the myModel object?
I'm guessing that you didn't, and you're just trying to use the class as a 'methods' class that doesn't store anything (I know there's a name for it, but I'm self taught so my terminology is pretty horrible!)
You can do this in objective-c, but you've got to use different syntax. Instead of using minus signs for the method declaration, use "+":
+(double)generateRandomNumber;
and now your method should be usable!

Simple iPhone tally method question

Just trying to create a simple method that counts up 1 on the tally when the button is pressed. My knowledge is extremely limited and I am pretty sure that my problem is somewhere in the method implementation:
-(IBAction) updateTally:(id) sender {
NSString *text;
int total = 0;
total = total + 1;
text=[[NSString alloc] initWithFormat: #"%i", total];
lblTally.text = text;
}
I have done the necessary interface declarations for the lblTally UILabel and the updateTally method. I suspect that there is some sort of an NSString/int/%i/%# mixup that I am making but I'm not sure how to fix it. When I run the program as it currently is it displays a 0 in the lblTally label field on the iphone. When I press the button it then displays a 1 in that field. However, if I continue to press the button - nothing happens, it just remains a 1. How do I make it count up as I continually press the button over and over?
The problem is that you are reinitializing the total in each updateTally. You need to either store the tally in a member variable or extract the existing tally from the string, update it, then write it back to the string.
- (IBAction) updateTally:(id) sender
{
int oldtally = [lblTally.text integerValue];
int newtally = oldtally + 1;
lblTally.text = [NSString stringWithFormat:"%d",newtally];
}
I should also point out that your current code has a memory leak (you invoke alloc/init, but then you don't invoke release after you have assigned the result to the lblTally.text variable). You should either invoke [text release] after lblTally.text = text, or you should use stringWithFormat like I have used above, which uses autorelease so that the string does not need to be explicitly released (since it will be automatically released).
You are re-initialising the total variable each time the method runs.
int total = 0;
Move than line of code outside of the method. I dont do apple development but it'll be something like:
int total = 0;
-(IBAction) updateTally:(id) sender {
NSString *text;
total = total + 1;
text=[[NSString alloc] initWithFormat: #"%i", total];
lblTally.text = text;
}