Blank textField (Calculation) crashes app. - objective-c

I have an app that does a simple calculation from 2 text fields, the result is then displayed as label text. This is fine as long at each text field is populated, if no data is entered and the calculate button is pressed then the app closed. I assumed that blank would return a value of 0 and result would be displayed as 0. My code is as follows:
-(IBAction) tonerCalc: (id) sender{
NSString *tString;
int myInt = [textField1.text intValue];
int myInt1 = [textField2.text intValue];
int total = myInt/(myInt1/5);
tString = [[NSString alloc] initWithFormat:#"%i",total];
labelText.text = tString;
[tString release];
}
How can I stop the crash, I think it has something to do with the calculation. Any help is greatly appreciated.

intValue will return 0 because there is no number in the string. But then you're doing a division by zero.

You can put a check like
`if(![textField1.text isEqualToString:#""]|| ![textField2.text isEqualToString:#""])`
{
//perform calculation
}
else
{
//show alert that text field are empty
}
and if the condition is true then you can make your calculation do otherwise show alert.It will stop the crash.

Related

Setting UILabel Text Multiple Times Within A Loop

I'm fooling around in XCode, trying to learn a little about the iOS SDK and Objective-C.
I have this for loop below, and it should print out several values to the screen (depending on the amount of months chosen), but instead, it's only printing out the final value.
Can anybody point out why?
Thanks a bunch, in advance!
for (int i = 1; i <= myMonthsDouble; i++)
{
myPaymentAmount = (myBalanceDouble/10) + myInterestDouble;
myBalanceDouble -= myPaymentAmount;
//convert myPaymentAmount double into string named myPaymentAmountString
NSString *myPaymentAmountString = [NSString stringWithFormat:#"%f", myPaymentAmount];
NSString *paymentInformation = [[NSString alloc] initWithFormat:#"%# months, %# per month.", monthsString, myPaymentAmountString];
myInterestDouble = (myBalanceDouble * (myInterestDouble/100))/12;
self.label.text = paymentInformation;
}
It is only printing the last value to the screen because you only have one label. Each time you get to the end of the loop, you are setting that label's text which is overriding the last value. If you want to print all of them to the screen, you will need to have either multiple labels or you will have to append the strings together and put them in either a label or a UITextView that is formatted so that they can all be seen (most likely a text view but it can be done with a label.)
One example of doing this would be:
label.text = [label.text stringByAppendingString:newString];
numLines++; //this starts at 0;
and then at the end:
label.numberOfLines = numLines;

bad access playing back user recording synchronised with animation based on recording volume with array

I am trying to store an array based on audio input and then play animation frames corresponding to the input while the recording is played back.
The code is working up to now except after a while it crashes in the simulator and highlights
"CCLOG(#"adding image: %#", characterImageString);";
with this:
EXC_BAD_ACCESS (code=1, address=0xd686be8)
which is memory management I know but I am absolutely stumped.
if(isRecording){
int myInt;
NSString * characterImageString;
//get a number based on the volume input
float f = audioMonitorResults * 200; //convert max(0.06) to 12
f=((f/12)*10);
NSNumber *myNumber = [NSNumber numberWithDouble:(f+0.5)];
myInt = [myNumber intValue] + 1;
//create the image file name from the intiger we
//created from the audiomonitor results
if(myInt < 10){
characterImageString = [NSString stringWithFormat:#"fungus000%i.png",myInt];
} else if (myInt == 10){
characterImageString = [NSString stringWithFormat:#"fungus00%i.png",myInt];
}
CCLOG(#"adding image: %#", characterImageString);
//add each frame
[animationSequence addObject:characterImageString];
// print array contents
NSLog(#"animationSequence Array: %#", animationSequence);
// print array size
NSLog(#"animationSequence Number of Objects in Array: %u", [animationSequence count]); }
This is the code that plays as the audio is playing back:
-(void) updateAnimation:(ccTime) delta{
myFrame ++;
NSString *imageToDisplay;
imageToDisplay = animationSequence[myFrame];
CCTexture2D *currentTextureToDisplay = [[CCTextureCache sharedTextureCache] addImage:imageToDisplay];
[character setTexture:currentTextureToDisplay];
CCLOG(#"current texture to display: %#", currentTextureToDisplay);
if (myFrame >= [animationSequence count]) {
[self unschedule:#selector(updateAnimation:)];
}
Your characterImageString is nil if myInt > 10
The exception is thrown, because you're trying to print a variable, which hasn't been initialized.
You could try changing your code to something like this:
if(myInt < 10)
{
characterImageString = [NSString stringWithFormat:#"fungus000%i.png",myInt];
}
else if (myInt >= 10 && myInt < 100)
{
characterImageString = [NSString stringWithFormat:#"fungus00%i.png",myInt];
}
else if (myInt >= 100 && myInt < 1000)
{
characterImageString = [NSString stringWithFormat:#"fungus0%i.png",myInt];
}
else
{
characterImageString = [NSString stringWithFormat:#"fungus%i.png",myInt];
}
Obviously small debugging goes a long way. Could you add control printout for myInt before the line
if(myInt < 10){
to see the value of myInt before the crash?
if myInt is <= 0 your program has no protection for such case so resulting picture will not exist.
And for myInt > 10 the program will crash since NSString * characterImageString; is an automatic uninitialized variable of the random value.
hmmm ... some motherhood and apple pie , hard with the info available. Not certain what the initial float value is, so declare somewhere your min and max image numbers (say, kMinFrameNumber and kMaxFrameNumber). Since the float value could be anything at the start of your algorithm, add the following 'defensive' lines after computing myInt:
myInt=MAX(kMinFrameNumber,myInt);
myInt=MIN(kMaxFrameNumber,myInt);
then formatting :
characterImageString = [NSString stringWithFormat:#"fungus%04i.png",myInt];
finally, i doubt the exception is thrown at the highlighted line (that is where it is detected).
a. How did you declare the array animationSequence (is it retained?). If not, it could get autoreleased under your feet at some random interval, and you would be trying to send a message to a deallocated instance.
b. You should also check for bounds before addressing animationSequence
if(myFrame<[animationSequence count]-1) {
imageToDisplay = animationSequence[myFrame];
} else {
CCLOGERROR(#"Yelp ! addressing out of bounds!");
// terminate neatly here ! as in unschedule and return
}
c. check if your texture is nil before setting a sprite (it will accept a nil texture in cocos2d version 2.0) but, you are in the dark about the state of your code.

Dynamically created textfield validation

I'm trying to validate dynamically created text fields. The total number of textfields may vary.
The idea is to populate the empty fields with string like player 1, player 2 etc.. Here is what I try
-(IBAction)validateTextFields:sender
{
self.howManyPlayers = 3;
int emptyFieldCounter = 1;
NSMutableArray *playersNames = [NSMutableArray arrayWithCapacity:self.howManyPlayers];
while (self.howManyPlayers > 1)
{
self.howManyPlayers--;
UITextField *tmp = (UITextField *) [self.view viewWithTag:self.howManyPlayers];
if (tmp.text == nil)
{
[tmp setText:[NSString stringWithFormat:#"Player %d", emptyFieldCounter]];
emptyFieldCounter++;
}
[playersNames addObject:tmp.text];
}
}
The problems is that if I touch the button which invoke validateTextFields method. The first and the second textfield are populated with text Player 1 and Player 2, but the third field is not populated.
I notice also that if I type a text let's say in the second field touch the button then remove the text and again touch the button that field is not populated with text Player X.
How to make all that things to work correctly ?
change your code for two lines like this:
while (self.howManyPlayers >= 1) //edited line
{
UITextField *tmp = (UITextField *) [self.view viewWithTag:self.howManyPlayers];
if (tmp.text == nil)
{
[tmp setText:[NSString stringWithFormat:#"Player %d", emptyFieldCounter]];
emptyFieldCounter++;
}
[playersNames addObject:tmp.text];
self.howManyPlayers--; // moved line
}
I forgot ur second question, so edited my answer.
For that try with this. Change if (tmp.text == nil) with if (tmp.text == nil || [tmp.txt isEqualToString:#""])
The reason only two fields are populated is that you are only going through the while loop twice. It should be
while (self.howManyPlayers >= 1)
You should also move the decrement to the end of your while loop
while (self.howManyPlayers >= 1)
{
// other code here
self.howManyPlayers--;
}
For the second part of your question, I think when you delete the text from the control, it stops being nil and now becomes an empty string. So you need to check for an empty string as well as nil in your code.
if (tmp.text == nil || [tmp.txt isEqualToString:#""])

How to randomize two UITextField variables?

I have two textFields where the user types into some words.
Then, when pressing a button, i want the words to randomize and then the user displays the randomized result.
I have this code:
-(IBAction) randomInp{
NSString *first = firstField.text;
NSString *second = secondField.text;
NSString *result = //here it should randomize the words
//Display randomized word
textview.text = //should display result
}
where firstField and secondField are respectively the first and the second UITextFields. Then i don't know how to proceed!
I was thinking of set a switch condition. If it's 0 then returns *first, if it's 1 then returns *second. Am i right?
Any help appreciated
EDIT
Solved!
If anyone needs:
-(IBAction) randomInp{
NSString *first = firstField.text;
NSString *second = secondField.text;
int text = rand() % 2;
switch (text) {
case 0:
textview.text = first;
break;
case 1:
textview.text = second;
break;
default:
break;
}
}
EDIT 2
The answer that SSteve gave works great, too! For anyone who needs:
NSString *result = random() & 1 ? first : second;
To choose between two values you can use random() and check the value of a bit:
NSString *result = random() & 1 ? first : second;
Put a call to srandomdev() somewhere in your initialization code to avoid having the same sequence of values every time your program runs. You may also need #include <stdlib.h>

How to reveal text line by line - Xcode

I have a simple app, I have a button that when pressed will display separate lines of text on the screen. I set an int = 0 and use an if statement that will add 1 at each line. The issue I have is that all lines are displayed after 1 button press, I want 1 button press one line displayed, next button press next line displayed and so on:
int nmbr = 0;
int myInt1 = [textfield.text intValue];
if (nmbr == 0) {
tString = [[NSString alloc] initWithFormat:#"111111111111%i x 1 = %i",myInt1,myInt1];
nmbr++;
}
if (nmbr == 1){
tString1 = [[NSString alloc] initWithFormat:#"222222222222%i x 2 = %i",myInt1,myInt1*2];
nmbr++;
}
if (nmbr == 2){
tString2 = [[NSString alloc] initWithFormat:#"%i x 3 = %i",myInt1,myInt1*3];
nmbr++;
}
I am new to this so any help is greatly appreciated.
Update:
Thanks folks for your help so far, I am not sure that I have explained this issue well……possibly gone about programming it all wrong. I have only one button on screen and each time it is pressed it would change a blank label to a text string. I was incrementing in each if statement so that on the next button press as nmbr = 2 then text label 2 would be modified, press again nmbr = 3 text label 3 would be modified and so on. There appears to be no separation in the code so on the button press all text labels are modified. I am not sure if it is possible to code multiple actions on a single button or if there is a better way to do this.
I have tried else if statements but still no joy.
Move your nmbr++; to the end of the method instead of putting it in each if statement. If you don't want it to increment every time then use a bool to keep track of whether or not you want to increment it. Also, nmbr needs to be a member variable (i.e. class level) instead of method level. If it is method level then its state isn't saved between calls.
Your result is normal because you if test are coming one after each other. The program will go on the first if, incremented nmbr, go out of the if and hit the next if.
It can work by moving the nmbr incrementation out of the "if" (as mentioned by mydogisbox) but you will still have to declare the variable as static.
Something like this:
static int nmbr = 0;
int myInt1 = [textfield.text intValue];
if (nmbr == 0) {
tString = [[NSString alloc] initWithFormat:#"111111111111%i x 1 = %i",myInt1,myInt1];
}
if (nmbr == 1){
tString1 = [[NSString alloc] initWithFormat:#"222222222222%i x 2 = %i",myInt1,myInt1*2];
}
if (nmbr == 2){
tString2 = [[NSString alloc] initWithFormat:#"%i x 3 = %i",myInt1,myInt1*3];
nmbr = 0; // if you have no other lines and you want to start from begining when the user press the button more than 3 times.
}
nmbr++;
Create required number of buttons in Interface Builder, declare them into .h file, create methods for each button -(void)firstButtonClick:(UIButton)sender, -(void)secondButtonClick:(UIButton)sender and put your code into these methods.
The problem is that you're incrementing within the if and then letting it fall to the next. Look at the flow: nmbr is one, so execute that block, which increments nmber to 1, making the next block true also. Depending on your style guides or personal preferences, you could:
Change the later ifs to else if.
Move all the nmbr++s to after the last if.
Return after incrementing inside the if.