I have a little coding problem at the moment. I have a picker with 7 different options, currently for testing purposes I have a label that will display the chosen value of the picker.
The problem that I am having is that my label is only displaying whole numbers, not displaying the entire decimal number, can someone please help me so that I can obtain the full value of the chosen item in the picker?
Here is my code :
// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
return [tempList count];
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
return [tempList objectAtIndex:row];
}
- (void)pickerView:(UIPickerView *)pickerView
didSelectRow:(NSInteger)row
inComponent:(NSInteger)component {
CGFloat chosenValue;
switch (row) {
case 0:
chosenValue = 0.0000373;
break;
case 1:
chosenValue = 0.0000273;
break;
case 2:
chosenValue = 0.0000233;
break;
case 3:
chosenValue = 0.0000204;
break;
case 4:
chosenValue = 0.0000179;
break;
case 5:
chosenValue = 0.0000169;
break;
case 6:
chosenValue = 0.0000142;
break;
default:
chosenValue = 0;
break;
}
NSNumberFormatter *formatter = [[NSNumberFormatter alloc]init];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
self.testLabel.text = [formatter stringFromNumber:#(chosenValue)];
}
You need to specify the precision:
self.textLabel.text = [NSString stringWithFormat:#"%.7f", chosenValue];
The %f format specifier defaults to 5 decimal places.
And you probably need to change chosenValue to double to get enough significant digits.
Better yet, since you are using an NSNumberFormatter, set the number of decimals:
NSNumberFormatter *formatter = [[NSNumberFormatter alloc]init];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
formatter.minimumFractionDigits = 7;
Why did you not use NSString stringWithFormat method?
self.textLabel.text = [NSString stringWithFormat:#"%.10f", chosenValue];
Try this :
self.testLabel.text = [NSString stringWithFormat:#"%.10f",chosenValue];
instead of:
self.testLabel.text = [formatter stringFromNumber:#(chosenValue)];
Related
Trying to get the amount of time selected by a user from a UIDatePicker set to mode:"UIDatePickerModeCountDownTimer" in InterFace Builder. Some other stacks say to just check the value of the property countDownDuration on the object.
#property (weak, nonatomic) IBOutlet UIDatePicker *hereIsThePicker;
...
NSLog(#"%f", self.hereIsThePicker.countDownDuration);
But this value often reports a range of values, I've seen numbers such as 70, 80, 113, etc for a selection of "0 Hours, 0 Minutes". So apparently countDownDuration is not what I need.
Does anyone have any hints or clues on how to use UIDatePickerModeCountDownTimer and convert the selection to number of seconds selected? so 1 Minute Selected = 60 Seconds, or 1 Hour 5 Minutes Selected = 3900 seconds ?
Been trying to track this down for 2 days now and just can't seem to get my head around what is going on.
Here is a screenshot of an example application that I setup that just has these two components. You can see the IBOutlet, and a button with an IBAction that is fetching the time and NSLogging it to the bottom of the screen:
Finally after trying random stuff for days, the simple answer, for whatever reason is you need to set a value to countDownDuration, even if you don't need to:
[self.timerPicker setCountDownDuration:60.0f]; //Defaults to 1 minute
In your header .h file put this
#interface ViewController : UIViewController
{
__weak IBOutlet UIPickerView *datePick;
NSMutableArray *hoursArray;
NSMutableArray *minsArray;
NSTimeInterval interval;
}
- (IBAction)calculateTimeFromPicker:(id)sender;
in your .m file put this
- (void)viewDidLoad
{
[super viewDidLoad];
//initialize arrays
hoursArray = [[NSMutableArray alloc] init];
minsArray = [[NSMutableArray alloc] init];
NSString *strVal = [[NSString alloc] init];
for(int i=0; i<61; i++)
{
strVal = [NSString stringWithFormat:#"%d", i];
//NSLog(#"strVal: %#", strVal);
//Create array with 0-12 hours
if (i < 13)
{
[hoursArray addObject:strVal];
}
//create arrays with 0-60 mins
[minsArray addObject:strVal];
}
NSLog(#"[hoursArray count]: %d", [hoursArray count]);
NSLog(#"[minsArray count]: %d", [minsArray count]);
}
//Method to define how many columns/dials to show
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 2;
}
// Method to define the numberOfRows in a component using the array.
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent :(NSInteger)component
{
if (component==0)
{
return [hoursArray count];
}
else
{
return [minsArray count];
}
}
// Method to show the title of row for a component.
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
switch (component)
{
case 0:
return [hoursArray objectAtIndex:row];
break;
case 1:
return [minsArray objectAtIndex:row];
break;
}
return nil;
}
- (IBAction)calculateTimeFromPicker:(id)sender
{
NSString *hoursStr = [NSString stringWithFormat:#"%#",[hoursArray objectAtIndex:[pickerView selectedRowInComponent:0]]];
NSString *minsStr = [NSString stringWithFormat:#"%#",[minsArray objectAtIndex:[pickerView selectedRowInComponent:1]]];
int hoursInt = [hoursStr intValue];
int minsInt = [minsStr intValue];
interval = 0 + (minsInt*60) + (hoursInt*3600);
NSString *totalTimeStr = [NSString stringWithFormat:#"%f",interval];
}
I have an array of lattitudes and longitudes in my array,
NSArray *anArrayOfFloatObjects = [NSArray arrayWithObjects:
[NSNumber numberWithDouble:pinLocation1.latitude],
[NSNumber numberWithDouble:pinLocation1.longitude],
[NSNumber numberWithDouble:pinLocation2.latitude],
[NSNumber numberWithDouble:pinLocation2.longitude],
[NSNumber numberWithDouble:pinLocation3.latitude],
[NSNumber numberWithDouble:pinLocation3.longitude],
nil];
What I want to do is use a switch statement to go through the array (i.e. objectAtIndex..)
switch (self.anArrayOfFloatObjects objectAtIndex:) {
case :0
//switch the pin color to red
break;
case :2
//switch pin color to green
break;
default:
break;
}
This obviously doesnt work. Does anyone know any other way?
I believe what you are looking for is
[anArrayOfFloatObjects indexOfObject:number]
Maybe this code will help:
NSArray *anArrayOfFloatObjects; //Your array
for (NSNumber *number in anArrayOfFloatObjects) {
switch ([anArrayOfFloatObjects indexOfObject:number]) {
case :0
//switch the pin color to red
break;
case :2
//switch pin color to green
break;
default:
break;
}
}
EDIT:
Following #MikeS comment you can do something like this:
for (int index = 0; index < [anArrayOfFloatObjects count]; index++) {
switch (index) {
case :0
//switch the pin color to red
break;
case :2
//switch pin color to green
break;
default:
break;
}
}
Avoiding the need of calling [anArrayOfFloatObjects indexOfObject:number]
try fast enumeration
for(id item in anArrayOfFloatObjects){
NSLog(#"%#", item);
}
You can also look into NSArray's enumerateObjectsUsingBlock.
[yourArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(#"Index: %ld - Object: %#", idx, obj);
}];
Im trying to do the calculations using NSNumbers and keep track of the numbers that the user inputs..
The problem is that my app is not doing any calculations now after updated my code to append . the decimal value to value whenever the user press the dot button. Which can be found Append or Add the decimal point functionality in calculator.
I have seen that the proper way to keep track of the inputs from the user and do the calculation is using the NSNumber but as I'm really new to Objective-c I have been struggling understanding the use and implementing it.
So, hopefully someone could walk me through to find the proper solution.
This is the header...
int Method;
float SelectNumber;
float RunningTotal;
bool DecimalActived;
#interface ViewController : UIViewController{
IBOutlet UILabel *Screen;
}
-(IBAction)Number9:(UIButton *)sender;
-(IBAction)Dot:(UIButton *)sender;
#end
This is the the implementation file..
-(IBAction)Number9:(UIButton *)sender{
[self appendDigit:#"9"];
}
- (IBAction)Dot:(UIButton *)sender {
NSString *currentText = Screen.text;
if ([currentText rangeOfString:#"." options:NSBackwardsSearch].length == 0) {
[self appendDigit:#"."];
}
}
- (void)appendDigit:(NSString *)digit {
// handle two special cases: append to only zero means just replace
// but append decimal point to zero is a regular append
if ([self->Screen.text isEqualToString:#"0"] && ![digit isEqual:#"."]) {
self->Screen.text = digit;
} else {
self->Screen.text = [Screen.text stringByAppendingString:digit];
}
}
- (IBAction)Percent:(UIButton *)sender {
[self MySwitch];
Method = 5;
SelectNumber = 0;
DecimalActived = FALSE;
Screen.text = [NSString stringWithFormat:#"%.2g", RunningTotal];
}
- (IBAction)PositiveOrNegative:(UIButton *)sender {
[self MySwitch];
Method = 6;
SelectNumber = 0;
DecimalActived = FALSE;
Screen.text = [NSString stringWithFormat:#"%g", RunningTotal];
}
-(IBAction)Equals:(UIButton *)sender{
[self MySwitch];
Method = 0;
SelectNumber = 0;
DecimalActived = FALSE;
Screen.text = [NSString stringWithFormat:#"%g", RunningTotal];
}
-(IBAction)AllClear:(UIButton *)sender{
Method = 0;
RunningTotal = 0;
SelectNumber = 0;
Screen.text = [NSString stringWithFormat:#"0"];
}
- (double) MySwitch {
NSNumberFormatter SelectNumber = [[NSNumberFormatter alloc] init];
[SelectNumber setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber RunningTotal = [SelectNumber numberFromString:self->Screen.text];
if (RunningTotal == 0) {
RunningTotal = SelectNumber;
} else{
switch (Method) {
case 1:
RunningTotal = RunningTotal * SelectNumber;
break;
case 2:
RunningTotal = RunningTotal / SelectNumber;
break;
case 3:
RunningTotal = RunningTotal - SelectNumber;
break;
case 4:
RunningTotal = RunningTotal + SelectNumber;
break;
case 5:
RunningTotal = RunningTotal / 100;
break;
case 6:
if(RunningTotal > 0){
RunningTotal = - RunningTotal;
} else{
RunningTotal = + RunningTotal;
}
break;
default:
break;
}
}
return RunningTotal;
}
If you guys have any question or need more information regarding my program please feel free to ask and I will provide as much information as possible or answer any questions that you guys may have.. :)
The header should look more like this:
// this uses more conventional (lowercase) property names
// and removes a couple that looked extraneous
#interface ViewController : UIViewController
#property(strong,nonatomic) IBOutlet UILabel *screen;
#property(assign,nonatomic) NSInteger method;
#property(strong,nonatomic) NSNumber *runningTotal;
#end
As the user presses digits, decimal, minus sign, append to the screen label as you have it. When the user presses an operation button, record an integer for the operation and record the current (NSNumber) value of the screen label. To do a computation...
- (void)doComputation {
float screenF = [[self screenValue] floatValue];
float runningF = [self.runningTotal floatValue];
float result;
switch (self.method) {
case 1:
result = runningF * screenF;
break;
case 2:
result = (screenF == 0.0)? 0.0 : runningF / screenF;
break;
case 3:
result = runningF - screenF;
break;
case 4:
result = runningF + screenF;
break;
default:
break;
}
self.screen.text = [NSString stringWithFormat:#"%0.8f", result];
self.runningTotal = [NSNumber numberWithFloat:result];
}
(screen value, as you have it...)
- (NSNumber *)screenValue {
NSNumberFormatter *f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
return [f numberFromString:self.screen.text];
}
How does this work?
NSNumberFormatter SelectNumber = [[NSNumberFormatter alloc] init];
[SelectNumber setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber RunningTotal = [SelectNumber numberFromString:self->Screen.text];
if (RunningTotal == 0) {
RunningTotal = SelectNumber;
} else{
switch (Method) {
case 1:
RunningTotal = RunningTotal * SelectNumber;
break;
This code shouldn't even work. Either SelectNumber is a float or it's a NSNumberFormatter*
Building a custom UIPickerView for so I can let my users select time as 24 hours without having to go into the Settings app and turn on 24 hour time for the entire phone. Got some stubborn leaks of a couple strings and an array, and I could really use some help.
There are only three places where the arrays I'm creating with the strings are used. hours and minutes are both NSArray synthesized properties as well as ivars.
a) In viewWillAppear:animated, where the strings and arrays are actually created:
if (TwentyFourHourMode) {
//set up arrays for 24 hour picker
NSMutableArray *hoursMutable = [[NSMutableArray alloc] init];
NSString *hourString;
for (int i = 0; i < 24; i++) {
if (i < 10) {
hourString = [NSString stringWithFormat:#"0%i", i];
} else {
hourString = [NSString stringWithFormat:#"%i", i];
}
[hoursMutable addObject:hourString];
}
self.hours = [[NSArray alloc] initWithArray:hoursMutable];
[hoursMutable release];
NSMutableArray *minutesMutable = [[NSMutableArray alloc] init];
NSString *minuteString;
for (int i = 0; i < 60; i++) {
if (i < 10) {
minuteString = [NSString stringWithFormat:#"0%i", i];
} else {
minuteString= [NSString stringWithFormat:#"%i", i];
}
[minutesMutable addObject:minuteString];
}
self.minutes = [[NSArray alloc] initWithArray:minutesMutable];
[minutesMutable release];
//more stuff which does not leak or reference the arrays/strings in question
} else {
//unrelated crap
}
b) in my UIPickerView delegate methods - everything that uses these two arrays:
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 2;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
if (component == 0) {
return self.hours.count;
} else if (component == 1) {
return self.minutes.count;
} else {
return 0;
}
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
if (component == 0) {
return [self.hours objectAtIndex:row];
} else if (component == 1) {
return [self.minutes objectAtIndex:row];
} else {
return nil;
}
}
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component {
switch(component) {
case 0: return 44;
case 1: return 50;
default: return 44;
}
}
- (void) pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
if (component == 0) {
[hour24 release];
hour24 = [self.hours objectAtIndex:row];
[hour24 retain];
} else if (component == 1) {
[minute24 release];
minute24 = [self.minutes objectAtIndex:row];
[minute24 retain];
}
c) and last but not least, in dealloc:
//set arrays to nil
self.hours = nil;
self.minutes = nil;
//release arrays
[hours release];
[minutes release];
Analyze is coming up clean, but Instruments is telling me hourString, minuteString, and self.hours are all being leaked. What really drives me nuts is that self.minutes isn't being leaked and it appears to be the same format of code as self.hours - I even copy-pasted and still get the same leak/no leak combo.
I'll be damned if I can figure out where this is coming from. Any ideas? Any further code y'all might need to help? Thanks, guys!
Edit: EmptyStack's suggestion stopped self.hours and minuteString from being leaked, but hourString is still leaking and there's now a new leak in this code just below the stuff above in viewWillAppear:animated (self.incomingTime is a synthesized NSString property, all arrays here are initialized locally):
NSArray *splitStrings = [self.incomingTime componentsSeparatedByString:#":"];
NSString *hourToDisplay = [splitStrings objectAtIndex:0];
//set this here so it doesn't give a null value
hour24 = [[NSString alloc] initWithString:hourToDisplay];
NSString *minuteSplitter = [splitStrings objectAtIndex:1];
NSArray *splitMinutes = [minuteSplitter componentsSeparatedByString:#" "];
NSString *minuteToDisplay = [splitMinutes objectAtIndex:0];
minute24 = [[NSString alloc] initWithString:minuteToDisplay];
Edit 2: Oh, for crying out loud, now minuteString is leaking again. I'm going to bed before my head explodes. Any suggestions overnight would be most welcome.
The problems are in the following lines,
self.hours = [[NSArray alloc] initWithArray:hoursMutable];
self.minutes = [[NSArray alloc] initWithArray:minutesMutable];
It seems hours and minutes are "retained properties" and you are allocating objects while assigning it to the properties. For example on the first line, [NSArray alloc] increases the retainCount by 1 and the setter self.hours in turn increases the retainCount by 1. Finally the retainCount becomes 2, which causes the leak even after you release those objects. You can use convenience constructors in these cases.
self.hours = [NSArray arrayWithArray:hoursMutable];
self.minutes = [NSArray arrayWithArray:minutesMutable];
And even a simpler way is to directly assign those arrays like this,
self.hours = hoursMutable;
self.minutes = minutesMutable;
Okay, finally found it, for anyone stumbling across this in the future: hour24 and minute24 were not being properly released in dealloc, so it was leaking strings and arrays all over the place. I found it by commenting out the code posted in the 2nd edit and putting it back in line by line until the leak sprang up. Thanks for the suggestions!
I have a simple calculator app and I want it to be so that if the answer requires no decimal places, there are none, just whole numbers. If the answer was 2, I don't want it to say 2.000000, it should say 2. If it requires one decimal place, it should show to one decimal place for example 12.8 instead of 12.80. How would I do this? Here is my code.
btw, this is from a tutorial at http://www.youtube.com/watch?v=Ihw0cfNOrr4, not my own work.
viewcontroller.h
#import <UIKit/UIKit.h>
interface calcViewController : UIViewController {
float result;
IBOutlet UILabel *calculatorScreen;
int currentOperation;
float currentNumber;
}
-(IBAction)buttonDigitPressed:(id)sender;
-(IBAction)buttonOperationPressed:(id)sender;
-(IBAction)cancelInput;
-(IBAction)cancelOperation;
#end
in the .m
#import "calcViewController.h"
#implementation calcViewController
-(IBAction)buttonDigitPressed:(id)sender {
currentNumber = currentNumber *10 + (float)[sender tag];
calculatorScreen.text = [NSString stringWithFormat:#"%2f", currentNumber];
}
-(IBAction)buttonOperationPressed:(id)sender {
if (currentOperation ==0) result = currentNumber;
else {
switch (currentOperation) {
case 1:
result = result + currentNumber;
break;
case 2:
result = result - currentNumber;
break;
case 3:
result = result * currentNumber;
break;
case 4:
result = result / currentNumber;
break;
case 5:
currentOperation = 0;
break;
}
}
currentNumber = 0;
calculatorScreen.text = [NSString stringWithFormat:#"%2f", result];
if ([sender tag] ==0) result=0;
currentOperation = [sender tag];
}
-(IBAction)cancelInput {
currentNumber =0;
calculatorScreen.text = #"0";
}
-(IBAction)cancelOperation {
currentNumber = 0;
calculatorScreen.text = #"0";
currentOperation = 0;
}
One way is to use NSNumberFormatter to format your result instead of NSString's -stringWithFormat::
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:requiredDigits];
[formatter setMinimumFractionDigits:0];
NSString *result = [formatter stringFromNumber:[NSNumber numberWithFloat:currentNumber];
The easiest way is just use [[NSNumber numberWithFloat:] stringValue]
Example:
float someFloatValue;
NSString floatWithoutZeroes = [[NSNumber numberWithFloat:someFloatValue] stringValue];
If we use %g in place of %f will truncate all zeros after decimal point.
For example
[NSString stringWithFormat:#"%g", 1.201000];
Output
1.201
This should work
NSString *result = [#(currentNumber) description];
I had the same problem. This is the code snippet that solved it (looks a lot like Caleb's solution, but that one didn't work for me, so I had to add an extra line):
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
numberFormatter.numberStyle = kCFNumberFormatterDecimalStyle;
numberFormatter.maximumFractionDigits = 20;
numberFormatter.minimumFractionDigits = 0;
NSNumber *number = [[NSNumber alloc]init];
NSString *numberString = [numberFormatter stringFromNumber:number];
We can use another numberStyle and override its basic appearance, setting desired properties of an NSNumberFormatter.