Number formatting - iphone

Hi all I am using below method to get string from NSNumber
-(NSString *)stringFromNumber:(NSNumber *)number
{
NSLog(#"Input:---%#",number);
NSNumberFormatter *numFormatter = [[[NSNumberFormatter alloc] init] autorelease];
[numFormatter setMaximumFractionDigits:5];
[numFormatter setMinimumFractionDigits:2];
//[numFormatter setExponentSymbol:#"e"];
NSString *str_num = [numFormatter stringFromNumber:number];
NSLog(#"Output:---%#",str_num);
return str_num;
}
in console i am getting like below
Input:---2.940000057220459
Output:---2.94
Input:---2940.000057220459
Output:---2940.00006
Input:---2.940000057220459e-15
Output:---.00
Input:---2.940000057220459e-12
Output:---.00
Input:---2.940000057220459e-09
Output:---.00
Input:---2.940000057220459e-06
Output:---.00
Input:---0.002940000057220459
Output:---.00294
but I need the output to look like below for above inputs (order)
---2.94
---2940
---2.94e-15
---2.94e-12
---2.94e-6
---2.94e-9
---0.00294
How would I do it? Someone please help me.

i tried this
-(NSString *)stringFromNumber:(NSNumber *)number
{
NSLog(#"Input:---%#",number);
NSNumberFormatter *numFormatter = [[NSNumberFormatter alloc] init];
[numFormatter setMaximumFractionDigits:5];
[numFormatter setMinimumFractionDigits:2];
NSString *temp = [NSString stringWithFormat:#"%#",number];
NSRange range = [temp rangeOfString:#"e"];
if(range.length > 0){
[numFormatter setNumberStyle:NSNumberFormatterScientificStyle];
[numFormatter setExponentSymbol:#"e"];
}
NSString *str_num = [numFormatter stringFromNumber:number];
NSLog(#"Output:---%#",str_num);
return str_num;
}
and Got like this
Input:---2.940000057220459
Output:---2.94
Input:---2940.000057220459
Output:---2940.00006
Input:---2.940000057220459e-15
Output:---2.94e-15
Input:---2.940000057220459e-12
Output:---2.94e-12
Input:---2.940000057220459e-09
Output:---2.94e-9
Input:---2.940000057220459e-06
Output:---2.94e-6
Input:---0.002940000057220459
Output:---.00294

Take a look at NSNumberFormatter Class.
setMinimumFractionDigits:
setMinimumIntegerDigits:

Related

Obj-C Help on code to convert number (no known class method for selector)

Newbie on Obj-C here : )
I'm writing a code that converts numbers (mostly to control the zeros after the dot, 5.000 -> 5 or 5.00).
So, I got it to work but I really wanted to create a class to use it as I need.
Here is the working code:
MainViewController.h
currentNumber = currentNumber *10 + (float)[sender tag];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:2];
[formatter setMinimumFractionDigits:0];
NSString *convertedNumber = [formatter stringFromNumber:[NSNumber numberWithFloat:currentNumber]];
calculatorScreen.text = [NSString stringWithFormat:#"%#",convertedNumber];
So, I just want to create a class that will do that for me and return the convertedNumber.
Here what I have done:
FormatNumber.h
#interface FormatNumber: NSNumber
{
NSString *nf;
}
- (void) getNumber:(float)n1;
- (NSString *) retNumber;
#end
FormatNumber.m
#implementation FormatNumber;
-(void) getNumber:(float)n1
{
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:2];
[formatter setMinimumFractionDigits:0];
nf = [formatter stringFromNumber:[NSNumber numberWithFloat: n1]];
}
-(NSString *) retNumber; // As I cannot return something from void, I tried to do this way, don't know if it's the better
{
return nf;
}
#end
MainViewController.h (trying to pass and get the value from the class)
currentNumber = currentNumber *10 + (float)[sender tag];
NSString *convertedNumber = 0;
FormatNumber *n1 = [[FormatNumber alloc] init];
[FormatNumber getNumber:currentNumber]; // No known class method for selector 'getNumber'
convertedNumber = [FormatNumber retNumber]; // No known class method for selector 'retNumber'
calculatorScreen.text = [NSString stringWithFormat:#"%#",convertedNumber];
Also, if there is a simple way to write this code I would appreciate some insights : )
You can do it by using C-way, use %.2f(for 2 decimals) and/or %.4f(for four decimals) and %.0 for no decimal.
Here is a sample code for this.
float f=5.0000;
NSLog(#"res: %.2f", f); //5.00
NSLog(#"res: %.0f", f); //5

Date formatter for converting 14-sept-2011 in 14th Sept

I have a string 14-Sep-2011 In need to convert this 14th Sept. This date may be any date string. Is there any date formatter which allows me to convert date in my format. As if date is 1-Sept-2011 then I need 1st Sept, 2-Sept-2011 should say 2nd Sept.
Can anyone please suggest the solution.
Thanks
- (NSString *)ordinalSuffixFromInt:(int)number {
NSArray *cSfx = [NSArray arrayWithObjects:#"th", #"st", #"nd", #"rd", #"th", #"th", #"th", #"th", #"th", #"th", nil];
NSString *suffix = #"th";
number = abs(number % 100);
if ((number < 10) || (number > 19)) {
suffix = [cSfx objectAtIndex:number % 10];
}
return suffix;
}
Test:
- (void)test {
for (int day=1; day<=31; day++) {
NSLog(#"ordinal: %d%#", day, [self ordinalSuffixFromInt:day]);
}
}
You try the following code because I run successfully.
NSString *dateStr = #"14-Sep-2011";
NSDateFormatter *dtF = [[NSDateFormatter alloc] init];
[dtF setDateFormat:#"dd-MMM-yyyy"];
NSDate *d = [dtF dateFromString:dateStr];
NSDateFormatter *monthDayFormatter = [[[NSDateFormatter alloc] init] autorelease];
[monthDayFormatter setFormatterBehavior:NSDateFormatterBehaviorDefault];
[monthDayFormatter setDateFormat:#"d MMM"];
int date_day = [[monthDayFormatter stringFromDate:d] intValue];
NSString *suffix_string = #"|st|nd|rd|th|th|th|th|th|th|th|th|th|th|th|th|th|th|th|th|th|st|nd|rd|th|th|th|th|th|th|th|st";
NSArray *suffixes = [suffix_string componentsSeparatedByString: #"|"];
NSString *suffix = [suffixes objectAtIndex:date_day];
NSString *format = [NSString stringWithFormat:#"%d",date_day];
NSString *dateStrfff = [format stringByAppendingString:suffix];
NSLog(#"%#", dateStrfff);
[monthDayFormatter setDateFormat:#"MMM"];
NSString *ss = [monthDayFormatter stringFromDate:d];
NSLog(#"%#",ss);
NSString *final = [dateStrfff stringByAppendingString:ss];
NSLog(#"final string:---> %#",final);
This is a perfect solution that you want.
This will work for any number :
-(NSString *) ordinalSuffix: (NSInteger) day {
NSString *ordinalSuffix;
if(day%10 == 1 && day%100 != 11) ordinalSuffix = #"st";
else if(day%10 == 2 && day%100 != 12) ordinalSuffix = #"nd";
else if(day%10 == 3 && day%100 != 13) ordinalSuffix = #"rd";
else ordinalSuffix = #"th";
return ordinalSuffix;
}
Test :
-(void) test {
for(NSInteger i = 1; i < 200; i++)
NSLog(#"%d%#", i, [self ordinalSuffix:i]);
}
use it
NSString *string =#"14-Sep-2011";
NSArray *arr = [string componentsSeparatedByString:#"-"];
NSString *str1=[arr objectAtIndex:0];
str1=[str1 stringByAppendingString:#"th"];
NSString *final=[str1 stringByAppendingFormat:#" %#",[arr objectAtIndex:1]];

Optimise slow code - enumeration of dictionary

I have the following code that decodes a JSON string into an array of objects that I can then use in a UITableView.
At first I thought the JSON decoding was the slow part but it appears that it is not as the "Dictionary Done" appears almost immediately.
Any ideas on how to get that code to be a little faster?
-(void)parseJSON:(NSString *)jsonData{
NSLog(#"Start parsing");
NSDictionary *deserializedData = [jsonData objectFromJSONString];
NSLog(#"Dictionary Done");
NSArray *flights = [deserializedData valueForKeyPath:#"flights.flight"];
NSMutableArray *localArray = [[NSMutableArray alloc] init ];
NSString *lastFlightno =#"";
for (NSDictionary *flight in flights){
ArchiveFlight *aFlight = [[ArchiveFlight alloc] initWithFlightno:[flight objectForKey:#"flightno"] route:[flight objectForKey:#"route"]];
aFlight.flightID = [flight objectForKey:#"primary_key"];
aFlight.timeStamp = [aFlight niceDate:[flight objectForKey:#"timestamp"]];
if (![lastFlightno isEqualToString:aFlight.flightno]) {
[localArray addObject:aFlight];
}
lastFlightno =aFlight.flightno;
[aFlight release];
}
NSLog(#"End Parsing");
[self loadupTable:localArray];
self.flightArray = localArray;
[localArray release];
}
EDIT: Added timestamps
Timestamps of the NSLogs as follows...
2011-04-26 13:22:36.104 App[1778:707] Finished request
2011-04-26 13:22:36.109 App[1778:707] Start parsing
2011-04-26 13:22:36.128 App[1778:707] Dictionary Done
2011-04-26 13:22:37.713 App[1778:707] End Parsing
Sample of the JSON...
{"flights":[{"flight":{"flightno":"RYR54WP","timestamp":"2011-04-26 12:13:04","route":"EGNX-LEAL","primary_key":"836453"}},{"flight":{"flightno":"RYR24LU","timestamp":"2011-04-26 09:14:03","route":"EVRA-EGNX","primary_key":"831318"}},{"flight":{"flightno":"RYR39WH","timestamp":"2011-04-26 05:33:03","route":"EGNX-EVRA","primary_key":"825492"}},{"flight":{"flightno":"RYR7PX","timestamp":"2011-04-25 20:07:03","route":"LELC-EGNX","primary_key":"816703"}},{"flight":{"flightno":"RYR2VB","timestamp":"2011-04-25 16:57:06","route":"EGNX-LELC","primary_key":"810900"}},{"flight":{"flightno":"RYR3JN","timestamp":"2011-04-25 12:36:04","route":"GCTS-EGNX","primary_key":"802631"}},{"flight":{"flightno":"RYR8GV","timestamp":"2011-04-25 06:07:03","route":"EGNX-GCTS","primary_key":"792945"}},{"flight":{"flightno":"RYR82QR","timestamp":"2011-04-24 19:42:04","route":"EPKK-EGNX","primary_key":"783306"}},{"flight":{"flightno":"RYR51PV","timestamp":"2011-04-24 16:31:05","route":"EGNX-EPKK","primary_key":"777835"}},{"flight":{"flightno":"RYR53AQ","timestamp":"2011-04-24 14:09:05","route":"LIME-EGNX","primary_key":"773572"}},{"flight":{"flightno":"RYR1CX","timestamp":"2011-04-24 11:02:05","route":"EGNX-LIME","primary_key":"768285"}},{"flight":{"flightno":"RYR9ZW","timestamp":"2011-04-24 08:21:04","route":"LEGE-EGNX","primary_key":"764624"}},{"flight":{"flightno":"RYR63BC","timestamp":"2011-04-24 05:48:02","route":"EGNX-LEGE","primary_key":"761726"}},{"flight":{"flightno":"RYR7PX","timestamp":"2011-04-23 19:39:03"
Formatted sample:
{
"flights":[
{
"flight":{
"flightno":"RYR54WP",
"timestamp":"2011-04-26 12:13:04",
"route":"EGNX-LEAL",
"primary_key":"836453"
}
},
{
"flight":{
"flightno":"RYR24LU",
"timestamp":"2011-04-26 09:14:03",
"route":"EVRA-EGNX",
"primary_key":"831318"
}
}
]
}
EDIT 2:
So here is "niceDate" that is causing the slowdown!
-(NSString *)niceDate:(NSString *)oldDate{
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init]autorelease];
[formatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate *sourceDate = [formatter dateFromString:oldDate];
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateStyle:NSDateFormatterFullStyle];
[dateFormatter setTimeStyle:NSDateFormatterLongStyle];
NSString *timeString = [dateFormatter stringFromDate:sourceDate];
return [NSString stringWithFormat:#"%#",timeString];
}
Some things that come to mind:
NSArray *flights = [deserializedData valueForKeyPath:#"flights.flight"];
Do you need to use KVC? What is the structure of your JSON data?
ArchiveFlight *aFlight = [[ArchiveFlight alloc] initWithFlightno:[flight objectForKey:#"flightno"] route:[flight objectForKey:#"route"]];
aFlight.flightID = [flight objectForKey:#"primary_key"];
aFlight.timeStamp = [aFlight niceDate:[flight objectForKey:#"timestamp"]];
You always create an instance of ArchiveFlight and parse the timestamp…
if (![lastFlightno isEqualToString:aFlight.flightno]) {
[localArray addObject:aFlight];
}
…even though you don’t have to do that all the time. Depending on how many repeated flightnos you have, this can make a noticeable difference.
Why not read [flight objectForKey:#"flightno"], compare it to lastFlightno and, if and only if they’re different, create an instance, add it to the array, and release it?
Edit: Try the following KVC-free code:
NSArray *flights = [deserializedData objectForKey:#"flights"];
NSMutableArray *localArray = [[NSMutableArray alloc] init ];
NSString *lastFlightno =#"";
for (NSDictionary *flightWrapper in flights) {
NSDictionary *flight = [flightWrapper objectForKey:#"flight"];
NSString *flightno = [flight objectForKey:#"flightno"];
if (! [flightno isEqual:lastFlightno]) {
// create instance, add it to the array, release the instance
}
}
Edit: You’re creating and (auto)releasing two instances of NSDateFormatter inside this method. In general this would be okay, but since it is being executed >1K times there are two considerations: a) you’re creating/using/releasing those two instances >1K times when, in fact, you don’t have two, b) you should use an autorelease pool in your loop.
You should make this method a class method (or a function) since it doesn’t depend on the state of an instance of that class. Your formatters would be class (static) variables. For instance:
#implementation ArchiveFlight
static NSDateFormatter *formatter1; // choose better names!
static NSDateFormatter *formatter2;
+ (void)initialize {
if (self == [ArchiveFlight class]) {
formatter1 = [[NSDateFormatter alloc] init];
[formatter1 setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
formatter2 = [[NSDateFormatter alloc] init];
[formatter2 setDateStyle:NSDateFormatterFullStyle];
[formatter2 setTimeStyle:NSDateFormatterLongStyle];
}
}
+ (NSString *)niceDate:(NSString *)oldDate {
NSDate *sourceDate = [formatter1 dateFromString:oldDate];
NSString *timeString = [formatter2 stringFromDate:sourceDate];
return timeString;
// why +stringWithFormat:? It’s not necessary!
// return [NSString stringWithFormat:#"%#",timeString];
}
This fixes item a) but you really should use an autorelease pool inside your loop because the Cocoa methods you’re using return autoreleased objects. By using an autorelease pool for each iteration of your loop, you reduce the memory footprint of your code — although this could decrease performance as well. I suggest you try both with and without an inner autorelease pool.
for (NSDictionary *flightWrapper in flights) {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
…
[pool drain];
}

Memory problem in NSXMLParser (iPhone)

Hi I'm trying to parse an xml and use the currentElementValue inside a code to get an expiredate. This is the code.
if([elementName isEqualToString:#"utlop"]) {
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:0];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateStyle:NSDateFormatterShortStyle];
int numberOfDays = [currentElementValue intValue];
NSDate *expireDate = [now addTimeInterval:60*60*24*numberOfDays];
NSString *expireString = [dateFormat stringFromDate:expireDate];
NSLog(#"ExpiryString :%#", expireString);
//Add values to Vare
enVare.utlop = expireString;
enVare.enhet = enhet;
enVare.isDirty = NO;
//Add Vare
[appDelegate addVare:enVare];
//Releasing
[dateFormat release];
[enVare release];
enVare = nil;
[currentElementValue release];
currentElementValue = nil;
[expireString release];
expireString = nil;
This results in a memory leak, but Im new to objective C so I can't find the error. When I just do this, it works:
enVare.utlop = currentElementValue;
Do not release objects that are not owned by you. You own an object when u create them using new or alloc. Release only those objects that are created by you using these functions. Also make sure that you release such objects once you have finished using them.

Differing NSNumberFormatter behavior

Consider this code:
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
nf.numberStyle = NSNumberFormatterCurrencyStyle;
NSLocale *l = [[NSLocale alloc] initWithLocaleIdentifier:#"it_IT"];
nf.locale = l;
[l release];
nf.decimalSeparator = #",";
nf.currencySymbol = #"US$";
[nf setLenient:YES];
NSString *s = #"US$ 0,05";
double d = [[nf numberFromString:s] doubleValue];
NSLog(#"%.2f",d);`
If I execute this in a normal Cocoa console-based application (10.6 sdk), I get the output "0.05" to the debug console.
However, if I execute this in the iPhone environment (OS 3.1.3), I get "0.00" output to the debug console. Am I doing something wrong with my usage of NSNumberFormatter? Or is this a discrepancy between the two platforms?
NSString *s = #"US$ 0,05";
What if you remove the space?