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 :)
Related
I am currently making a game in sprite kit and i have 8 methods, I have written all the timing code E.T.C so it calls a method every 1 second, but i want it to call a random one of the eight methods, I have been trying to get this working for weeks, any help would be muchly appreciated, Here is my timing code -
- (void)updateWithTimeSinceLastUpdate:(CFTimeInterval)timeSinceLast {
self.lastSpawnTimeInterval += timeSinceLast;
if (self.lastSpawnTimeInterval > 5) {
self.lastSpawnTimeInterval = 0;
[self shoot1];
}
}
- (void)update:(NSTimeInterval)currentTime {
// Handle time delta.
// If we drop below 60fps, we still want everything to move the same distance.
CFTimeInterval timeSinceLast = currentTime - self.lastUpdateTimeInterval;
self.lastUpdateTimeInterval = currentTime;
if (timeSinceLast > 1) { // more than a second since last update
timeSinceLast = 1.0 / 60.0;
self.lastUpdateTimeInterval = currentTime;
}
[self updateWithTimeSinceLastUpdate:timeSinceLast];
}
As you can see instead of [self shoot1]i want it to randomly call one of the eight methods, Also all the methods are named Shoot1, Shoot2, all the way to Shoot8. Thankyou
I can think of two options...
Option 1
Just pick a random number between 1 and 8, and use a switch statement:
- (void)updateWithTimeSinceLastUpdate:(CFTimeInterval)timeSinceLast {
self.lastSpawnTimeInterval += timeSinceLast;
if (self.lastSpawnTimeInterval > 5) {
self.lastSpawnTimeInterval = 0;
int randomNumber = arc4random_uniform(8);
switch(randomNumber) {
case 0:
[self shoot1];
break;
case 1:
[self shoot2];
break;
// ... cases 2-6
case 7:
[self shoot8];
break;
}
}
}
Option 2
Rewrite your shootN methods so that you only have one method that takes an integer as a parameter:
- (void)shoot:(int)index;
Then, you can just do the following:
[self shoot:arc4random_uniform(8)];
You could also live dangerously...
int random = arc4random() % 8;
NSString *selectorName = [NSString stringWithFormat:#"shoot%i", random];
SEL selector = NSSelectorFromString(selectorName);
if ([self respondsToSelector:selector]) {
[self performSelector:selector];
}
This will, by the way, generate a warning when using ARC.
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 ==
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.
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;
}
}
Why isn't my UILabel being changed? I am using the following code, and nothing is happening:
- (void)awakeFromNib {
percentCorrect.adjustsFontSizeToFitWidth;
percentCorrect.numberOfLines = 3;
percentCorrect.minimumFontSize = 100;
}
Here is my Implemintation code:
- (void) updateScore {
double percentScore = 100.0 * varRight / (varWrong + varRight);
percentCorrect.text = [NSString stringWithFormat:#"%.2f%%", percentScore];
}
- (void)viewDidLoad {
percentCorrect.adjustsFontSizeToFitWidth = YES;
percentCorrect.numberOfLines = 3;
percentCorrect.minimumFontSize = 100;
percentCorrect.text = #"sesd";
}
- (void)correctAns {
numberRight.text = [NSString stringWithFormat:#"%i Correct", varRight];
}
-(void)wrongAns {
numberWrong.text = [NSString stringWithFormat:#"%i Incorrect", varWrong];
}
#pragma mark Reset Methods
- (IBAction)reset:(id)sender; {
NSString *message = #"Are you sure you would like to reset?";
self.wouldYouLikeToReset = [[UIAlertView alloc] initWithTitle:#"Reset?" message:message delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:nil];
[wouldYouLikeToReset addButtonWithTitle:#"Continue"];
[self.wouldYouLikeToReset show];
// Now goes to (void)alertView and see's what is being pressed!
}
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0)
{
NSLog(#"Cancel button pressed");
}
else
{
varRight = 0;
varWrong = 0;
[self wrongAns];
[self correctAns];
percentCorrect.text = [NSString stringWithFormat:#"0.0%%"];
}
}
#pragma mark Button Action Methods
- (IBAction)right:(id)sender; {
varRight++;
[self correctAns];
[self updateScore];
}
- (IBAction)wrong:(id)sender; {
varWrong++;
[self wrongAns];
[self updateScore];
}
- (IBAction)subOneRight:(id)sender {
if (varRight > 0 ) {
varRight--;
[self correctAns];
[self updateScore];
}
}
- (IBAction)subOneWrong:(id)sender {
if (varWrong > 0) {
varWrong--;
[self wrongAns];
[self updateScore];
}
}
-(IBAction)addHalfCredit:(id)sender;
{
varWrong++;
varRight++;
[self wrongAns];
[self correctAns];
[self updateScore];
}
#end
Any ideas?
Thanks
In order for the adjustsFontSizeToFitWidth setting to come into effect, the numberOfLines property must be set to 1. It won't work if it's != 1.
Are awakeFromNib, viewDidLoad, viewWillAppear being called at all?
The minimumFontSize property will do nothing if the text fits in the current bounds with the current font. Did you set the font property for the label?
percentCorrect.font = [UIFont systemFontOfSize:20];
Finally, isn't a minimumFontSize = 100 a little too big for a min font size?
Make sure everything is hooked up correctly. Make sure the IBOutlet for the UITextfield is setup and set break points within the method and see that the code is being touched. If it is, it's possible percentCorrect hasn't been hooked up correctly.
You shouldn't have to init your label if it is in the nib. If you are, then you created the label twice. So who knows which one you are messaging to. As soon as you initialized the label, you leaked the first one. So the label you have on screen is NOT the one you are manipulating in code.
Try placing your code in viewDidLoad instead. It should be initialized by then.
If that doesn't work, try viewDidAppear: simply to try to debug this.
It's possible that percentCorrect hasn't yet been initialized. Is percentCorrect equal to nil when that function is called, by any chance? If so, wait until after it's properly initialized to set its properties.
What are you expecting to happen? Does the label show when your code is commented out? How is percentCorrect defined in the nib?
Have you tried:
- (void)awakeFromNib {
percentCorrect.adjustsFontSizeToFitWidth = YES;
percentCorrect.numberOfLines = 3;
percentCorrect.minimumFontSize = 100;
percentcorrent.text = #"What is the text in percentCorrect?";
}
I had the same problem. Seems that setText doesn't automatically force a redraw when the change happens on a non-main thread. UI updates should always be done on the main thread to ensure responsiveness. There's another way to force it, using a selector:
label = [[UILabel alloc] init]; //assumes label is a data member of some class
...
(some later method where you want to update the label)
...
[label performSelectorOnMainThread:#selector(setText) withObject:#"New label value" waitUntilDone:false];
You may also get results from simply saying:
[label setNeedsDisplay];
which will force the update internally, but at the SDK's discretion. I found that didn't work for me, thus why I recommend the selector on the main thread.
What I found is sometimes , don't rely too much on IB , just add a line to set the frame :
labelx.frame=CGRectMake(labelx.frame.origin.x,labelx.frame.origin.y, 300, labelx.frame.size.height);
Then , autoresize works !