Changing button label not working properly with if-else method - iphone

it is probably a very simple problem but I spent already a lot of time on it and just have given up...
I have a button and a textfield for speed calculations. I want the button label change once the button is pressed (km/h >> mph >> m/s >> km/h and so on) and speed recalculated. It sometimes works fine but very often it jumps to "else" statement even if the CurrentSpeedValue is #"km/h". Could anyone help? Maybe it would be better to use switch-case method but how should it be stated?
- (IBAction)speedChange:(id)sender {
//CurrentSpeedUnit is saved to NSUserDefault in another action
if (CurrentSpeedUnit == #"km/h") {
[sender setTitle:#"mph" forState:UIControlStateNormal];
CurrentSpeedUnit = #"mph";
float speedToPrint = ([textSpeed.text floatValue]) / 1.609344;
textSpeed.text = [[NSString alloc] initWithFormat:#"%.3f", speedToPrint];
} else if (CurrentSpeedUnit == #"mph") {
[sender setTitle:#"m/s" forState:UIControlStateNormal];
CurrentSpeedUnit = #"m/s";
float speedToPrint = ([textSpeed.text floatValue]) * 1.609344 / 3.6;
textSpeed.text = [[NSString alloc] initWithFormat:#"%.3f", speedToPrint];
} else {
[sender setTitle:#"km/h" forState:UIControlStateNormal];
CurrentSpeedUnit = #"km/h";
float speedToPrint = ([textSpeed.text floatValue]) * 3.6;
textSpeed.text = [[NSString alloc] initWithFormat:#"%.3f", speedToPrint];
}
}

For string comparison you need to use
isEqualToString
For Example:
if ([CurrentSpeedUnit isEqualToString:#"km/h"])
{
// Perfrom Action
}...

You should not compare strings like that (you compare pointers but not the contents). Use isEqualToString.
i.e.
if ([CurrentSpeedUnit isEqualToString:#"km/h"]) {
...
but not your
if (CurrentSpeedUnit == #"km/h") {
It may work sometimes, but just remember to avoid comparing strings with ==

Related

Reduce number in text box by one for each button tap

I'm relatively new to Objective-C so this might be really simple to do: I have a text box in my application that displays an ammo count, so each time the user taps a fire button the number in the text box will go down by one (12 > 11 > 10, etc) to 0. I have tried using for and if statements, but they are not working (I may have used incorrect syntax). This is what I'm using right now, but obviously I need the
- (IBAction)fire {
[ammoField setText:#"11"];
}
- (IBAction)reload {
[ammoField setText: #"12"];
}
The simplest way would be to convert the text to a number, decrement that and the reset the text, i.e. replace the code in the fire method with:
NSInteger ammoCount = [ammoField.text integerValue];
ammoCount--;
ammoField.text = [NSString stringWithFormat:#"%d", ammoCount];
But don't do this, it will make baby Steve Jobs cry.
A better way would be to add a new variable to the class of type UIInteger that tracks the the number of bullets, i.e.:
// in interface
NSInteger _ammoCount;
...
// in implementation
- (IBAction)fire {
_ammoCount--;
if (_ammoCount <= 0) {
_ammoCount = 0;
fireButton.enabled = NO;
}
[ammoField setText: [NSString stringWithFormat:#"%d", _ammoCount]];
}
- (IBAction)reload {
_ammoCount = 12;
[ammoField setText: [NSString stringWithFormat:#"%d", _ammoCount]];
fireButton.enabled = YES;
}
Oh, and don't forget to call reload at some point early on to ensure _ammoCount and ammoField get initialised.
Set Instance Integer
int x;
set value of it
x = 12;
do change in method
- (IBAction)fire {
[ammoField setText:[NSString stringWithFormat:#"%i",x]];
x--;
}
set the value of count in viewdidload with an int variable
fire method decrease the count by 1
and reload method to return value to 12
log or use values accordingly
Try this:-
int i;
-(void)ViewDidLoad
{
i=12;
}
- (IBAction)fire
{
[ammoField setText:[NSString stringWithFormat:#"%d",i]];
i--;
}
- (IBAction)reload {
i = 12;
[ammoField setText: [NSString stringWithFormat:#"%d", i]];
}
Hope it will work for you. Thanks :)

How do i toggle UIButton using currentTitle in XCode

To the point, i have 10 button and i write a number in Title inside every button, that is 0 to 9. My problem in here is, how do i toggle a button function, just say when i press a number 0, the value will show in showLabel.text is 0 and the button is in selected state but when i push it again, the number is gone in showLabel.text and the button is change back to normal state. I using this below code but it can't solve my problem. I mean, just say i selected number "1, 5, 7, 8" and i want to deselect number 5, using below code my showLabel will replace all number to none not to be "1, 7, 8". So i think this is not good idea using this code.
-(IBAction)numberBtn:(UIButton *)sender
{
UIButton *button = (UIButton *)sender;
[button setTitle:#"X" forState:UIControlStateSelected];
button.selected = !button.selected;
if (button.selected)
{
number = sender.currentTitle;
showLabel.text = [showLabel.text stringByAppendingFormat:number];
}
else
{
showLabel.text = [NSString stringWithFormat:#""];
}
}
Is there anyway to do that? Happy holiday.
Well. A think it will be good idea to make an array of 10 Boolean values and every time your button has been pressed - you just need to toggle corresponded value in your Boolean array and update your label using "for" loop:
for (int nn=0; nn<10; ++nn) if (boolVals[nn]) [myString appendFormat #"%d ", nn];
Do this instead:
- (IBAction)numberBtn:(UIButton *)sender {
sender.selected = !sender.selected;
if (sender.selected)
{
NSString *number = sender.currentTitle;
showLabel.text = [showLabel.text stringByAppendingString:number];
}
else
{
NSString *newString;
NSString *number = sender.currentTitle;
NSString *string = showLabel.text;
for (int i = 0; i<string.length; ++i) {
NSString *sub = [string substringWithRange:(NSRange){i, 1}];
if ([sub isEqualToString:number]) {
newString = [string substringToIndex:i];
newString = [newString stringByAppendingString:[string substringFromIndex:i+1]];
}
}
showLabel.text = newString;
}
[sender setTitle:#"X" forState:UIControlStateSelected];
}

Dynamically Add Textfield with tag On button Part-2

I want to add a textfield dynamically with tag so that it can give unique value every time. And than add those values and show on label. When I click button one textfield add "n" give the value, and that value adds to the previous value.
Value adding Successfully. But when I edit anything, change or give another value such as (10 instead of 12) the loop will run again because of this line
[Txt_New_Estimated addTarget:self action:#selector(C6Loop) forControlEvents:UIControlEventEditingDidEnd];
2nd problem is that when I add a new textfield then the previous textfield did not modify and do not add in rest of textfields... before adding a new textfield it works properly but when edit anything loop will run again.... i want to overCome this problem, so please check this code and give some possible solution. I am sending my code here Please check this code.
-(void)CreateTextFeildOnRun
{
if (tag ==0)
{
textPosY = 420;
}
for ( i =tag; i<= tag; i++)
{
Txt_New_Estimated = [[UITextField alloc]initWithFrame:CGRectMake(360, textPosY , 130, 65)];
Txt_New_Estimated.delegate = self;
Txt_New_Estimated.text=#"";
//[Txt_New_Estimated setTag:1234];
Txt_New_Estimated.tag = i;
Txt_New_Estimated.clearButtonMode = UITextFieldViewModeWhileEditing;
[Txt_New_Estimated addTarget:self action:#selector(C6Loop) forControlEvents:UIControlEventEditingDidEnd];
Txt_New_Estimated.placeholder = #"Estimated";
Txt_New_Estimated.font = [UIFont fontWithName:#"Arial" size:23];
Txt_New_Estimated.backgroundColor = [UIColor whiteColor];
Txt_New_Estimated.textAlignment = UITextAlignmentCenter;
[scrollview addSubview:Txt_New_Estimated];
}
}
-(void)C6Loop{
Txt_New_ONU.text=Txt_New_Estimated.text;
[self Calculate2];
}
-(void)Calculate2{
int y14=([Txt_New_Estimated.text intValue]);
y14=n;
n=d;
c14= y14+([Txt_New_Estimated.text floatValue]);
n = c14;
[self addest];
}
-(void)addest{
float c1= ([Txt_Engring_Est.text floatValue]) + ([Txt_Weddring_Est.text floatValue]) + ([Txt_Bridal_Est.text floatValue])+ ([Txt_Veil_Est.text floatValue])+ ([Txt_Shoe_Est.text floatValue])+n;
Txt_Total_Est.text = [[NSString alloc] initWithFormat:#"%.2f",c1];
}
Thank You.
Why don't you add those TextField when created to to an NSMutableArray. something like this:
-(void)createTextFieldOnRun
{
if (tag ==0)
{
textPosY = 420;
}
for ( i =tag; i<= tag; i++)
{
UITextField *Txt_New_Estimated = [[UITextField alloc]initWithFrame:CGRectMake(360,textPosY ,130,65)];
Txt_New_Estimated.delegate = self;
//....other code..
[scrollview addSubview:Txt_New_Estimated];
[textFieldArray addObject:Txt_New_Estimated];
}
}
and when calculating do something like this:
int result = 0;
for(UITextField *field in textFieldArray) // will iterate all UITextField which was added
{
result += [field.text intValue]; //or floatValue
}
NSLog(#"the result is %d", result); //here you have sum of all the text fields' text
It doesn't matter whether you change the value or not, it will recalculate all the values.

Hiding or moving SegmentContoller

Hello I've tried for 3 weeks to solve this issue and it stumps me. What i am trying to do is create a 3 part segment from an array, display it in a view in a certain position, then remove it from view when the "OFF" flag is set. Every thing works except the removal of the segment. It will even commuticate with (pickOne) and display the segment letters in a label. What i can't get to work is either of the two: setHidden:YES, or removeAllSegments. Any help would be appreciated. Here is my code.
- (void) showSegment {
int x = 192;
int y = 212;
int w = 125;
int h = 25;
SegUnit1 = #"A";
SegUnit2 = #"B";
SegUnit3 = #"C";
threeSegs = [NSArray arrayWithObjects: SegUnit1, SegUnit2, SegUnit3, nil];
segSize = [NSArray arrayWithArray:threeSegs];
UISegmentedControl *heightSC = [[UISegmentedControl alloc] initWithItems:segSize];
if ([segmentState_height isEqualToString:#"ON"]) {
NSLog(#"segmentState_height = %#",segmentState_height);
heightSC.frame = CGRectMake(x, y, w, h);
heightSC.segmentedControlStyle = UISegmentedControlStyleBar;
heightSC.selectedSegmentIndex = -1;
[heightSC addTarget:self
action:#selector(pickOne:)
forControlEvents:UIControlEventValueChanged];
[self.view addSubview:heightSC];
[heightSC release];
} else if ([segmentState_height isEqualToString:#"OFF"]) {
NSLog(#"segmentState_height = %#",segmentState_height);
[heightSC setHidden:YES]; // NSLog showing "OFF" but segment will not hide.
[heightSC removeAllSegments]; // NSLog showing "OFF" and segment is suppose to dismantle and does not.
}
}
I know now that i have to "not" create and remove in the same function, and was given a tip on correcting this but I don't know how to use the tip.
here is what was suggested.
Well, your method is a little confused, since you are trying to both create and hide at the same time. So you might consider splitting that up into separate methods.
In general, it will be along these lines:
Code:
if ([self theControlProperty] == nil)
{
UISeg... *theControl = [[UISeg alloc] ....];
[self setTheControlProperty:theControl];
...
}
if (shouldHideTheControl)
{
[[self theControlProperty] setHidden:YES];
}
Any help would be appreciated.
The problem you have is that you're creating a new UISegmentedControl instance every time that method is called. The first time through, you create an instance and add it as a subview to your view. This apparently works fine, as it should. Then the method returns, and you no longer have any easy way to refer to that instance that you created. When you re-enter -showSegment, you create a different instance, and then hide and/or destroy it. This different instance has no effect whatsoever on the instance that you gave to the view.
What you need to do is make heightSC an instance variable. Add it to the interface declaration in the header file, then initialize it only once, and hide or modify it as needed subsequently. The key point is that you need to have a reference to the instance of the UISegmentedControl which is being drawn on the screen, a reference that lives outside the method itself that you can use the second, third, fourth, etc time you call that method.
Try using the remove segments in your button choice method pickOne. This takes it outside the showSegment method and matches the users desired action to make the change and clear off the buttons.
- (void) pickOne:(id)sender {
UISegmentedControl* userChose = sender;
if( [userChose selectedSegmentIndex] == 0 ){
your first button operation;
[heightSC removeAllSegments];
}
if( [userChose selectedSegmentIndex] == 1 ){
your second button operation;
[heightSC removeAllSegments];
}
if( [userChose selectedSegmentIndex] == 2 ){
your third button operation;
[heightSC removeAllSegments];
}
}
I tried this and got the results I was looking for. Thanks goes to Mythogen and BrianSlick I just need to check and make sure there are no leaks. Now that will be a task.
Does anyone know if I need the second [heightSC release]; ?
// .h
# interface ------ {
UISegmentedControl *segmentPicked;
}
|
#property (nonatomic, retain) UISegmentedControl *segmentPicked;
// .m
|
#synthesize segmentPicked;
|
if ([self segmentPicked] == nil) {
UISegmentedControl *heightSC = [[UISegmentedControl alloc] initWithItems:segSize];
[self setSegmentPicked:heightSC];
[heightSC release];
heightSC.frame = CGRectMake(x, y, w, h);
heightSC.segmentedControlStyle = UISegmentedControlStyleBar;
heightSC.selectedSegmentIndex = -1;
[heightSC addTarget:self
action:#selector(pickOne:)
forControlEvents:UIControlEventValueChanged];
[self.view addSubview:heightSC];
[heightSC release];
}
if ([segmentState_height isEqualToString:#"OFF"])
{
[[self segmentPicked] setHidden:YES];
} else {
[[self segmentPicked] setHidden:NO];
}
[yourSegment removeFromSuperview];
?

How to get UIButtons title in an array to be shown each one by one in a timed sequence

In my program, I have a series of UIButtons in an array that I would like its title to be shown each one at a time one by one in a timed sequence after executing a function that has a while loop.
I have an IBAction attached to the buttons and when touched will call another function that will do some operation and in the end, will change the UIButtons title in that array.
The problem is that it changed the whole buttons title simultaneously after executing that method but I want the title to be shown one by one in a timed sequence.
To illustrate clearly, here are my codes:
-(IBAction)touchedButton1:(id)sender
{
[self calculateSteps:0];
}
-(void)calculateSteps:(NSUInteger)hole_index2
{
index = hole_index2;
NSNumber *tempNumber = [marblesArray objectAtIndex:index];
stones = [tempNumber intValue];
[marblesArray replaceObjectAtIndex:index withObject:[NSNumber numberWithInt:0]];
[[buttonsArray objectAtIndex:index] setTitle:[NSString stringWithFormat:#"%d", [NSNumber numberWithInt:0].intValue] forState:UIControlStateNormal];
while(stones > 0) {
if (player == PLAYER_A && stones >= 1 && index == 6) {
NSNumber *tempNumber3 = [storeArray objectAtIndex:0];
NSUInteger tempInt3 = [tempNumber3 intValue];
tempInt3++;
[storeArray replaceObjectAtIndex:0 withObject:[NSNumber numberWithInt:tempInt3]];
[buttonPlayerA setTitle:[NSString stringWithFormat:#"%d", [NSNumber numberWithInt:tempInt3].intValue] forState:UIControlStateNormal];
stones--;
if (stones == 0) { // end in PLAYER A's store
NSLog(#"end in big hole player A");
return;
}
}
if (player == PLAYER_B && stones >= 1 && index == 12) {
NSNumber *tempNumber4 = [storeArray objectAtIndex:1];
NSUInteger tempInt4 = [tempNumber4 intValue];
tempInt4++;
[storeArray replaceObjectAtIndex:1 withObject:[NSNumber numberWithInt:tempInt4]];
[buttonPlayerB setTitle:[NSString stringWithFormat:#"%d", [NSNumber numberWithInt:tempInt4].intValue] forState:UIControlStateNormal];
stones--;
if (stones == 0) { // end in PLAYER B's store
NSLog(#"end in big hole player B");
return;
}
}
index++;
if (index >= NUM_HOLES) index = 0;
NSNumber *tempNumber2 = [marblesArray objectAtIndex:index];
tempInt2 = [tempNumber2 intValue];
tempInt2++;
[marblesArray replaceObjectAtIndex:index withObject:[NSNumber numberWithInt:tempInt2]];
NSLog(#"Number in marblesArray index: %d", [NSNumber numberWithInt:tempInt2].intValue);
[[buttonsArray objectAtIndex:index] setTitle:[NSString stringWithFormat:#"%d", [NSNumber numberWithInt:tempInt2].intValue] forState:UIControlStateNormal];
stones--;
}
}
So, I have tried to put NSTimer in the calculateSteps method and also in that while loop but couldn't get to work. I guess maybe the while loop function fast enough that it didn't get the chance to get NSTimer to work in time.
I know it could work if I use if timer == 1, or else if timer == 2, etc as the timer increase, each button associated with it will change after that interval. However, when I tried to use for (timer == 1; timer < stones; timer++) , it doesn't show the buttons title each one by one but simultaneously after it is done with the loop. Am I wrong with my logic?
Also, I've tried to put sleep(2) in the while loop also, it works for the NSLog(#"Number in marblesArray index:...") appearing each 2 seconds but still the buttons array title still shown simultaneously after while loop completed.
I'm not sure how can I get the buttons title in that array to be shown each one by one in a timed sequence. Have been trying for 2 days but couldn't get it to work.
Appreciate if anyone out there who can help me. I don't know if it's my logic or if there's other function that can be used to solve this issue.
Thank you very much in advance.
Yes, you could used :
NSTimer
or just performSelector:withObject:afterDelay: of any NSObject subclass.
You can not use sleep or loop in main thread. It will block the HMI.
But I don't really understand your code and your explanation...
In the target selector of the timer, you could have a static int to count the number of ticks
example (very simple):
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(onTimer) userInfo:nil repeats:NO];
-(void)onTimer{
static int ticks = 0;
ticks++;
if (ticks==1) {
//TODO
} else if (ticks==2) {
//TODO
} else if (ticks==3) {
//TODO
} else {
//TODO
ticks=0;
}
}