Convert CFBundleVersion to NSNumber & compare it [duplicate] - objective-c

This question already has answers here:
Compare version numbers in Objective-C
(15 answers)
Closed 9 years ago.
Before asking why: I'm writing an extension that observes the CFBundleVersion of an app & then compares it to old version that isn't supported by the extension.
Here's what I do to compare.
CFStringRef _version = CFURLCreateStringByAddingPercentEscapes(NULL,
(__bridge CFStringRef)[[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleVersion"],
NULL,
(CFStringRef)#" !*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8);
NSString *versionString = (NSString *)CFBridgingRelease(_version);
NSNumberFormatter * nsFormatter = [[NSNumberFormatter alloc] init];
[nsFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber * installedVersion = [nsFormatter numberFromString:versionString];
NSNumber * incompatibleVersion = [nsFormatter numberFromString:#"6.1.0"];
if (installedVersion <= incompatibleVersion) {
NSLog(#"This was triggered");
}
The code works great, but only when there are two decimals. For instance, if I set the CFBundleVersion to 6.0 or 5.0 The code is not triggered. Is there a better way of comparing? I don't understand why it's thinking 5.0 is greater than 6.1.0
Suggestions?

You obviously can't treat it as one number, so treat it as a set of numbers with a separator. Then, you can use componentsSeparatedByString:#"." and process each of the numbers separately.
Be sure to check the count of the components. If one number has more components than the other you should fall back to default values (0) if you haven't already got a result from the algorithm.
Loop over the components and compare each part.

Versions in the format major.minor.patch cannot generally be represented as a single number. It's best to compare the strings using ...
[version1 compare:version2 options:NSNumericSearch];
This only works if the number of components is always the same.

Related

put coma on every 3rd number like in calculator. objective-c [duplicate]

This question already has answers here:
NSNumberFormatter with comma decimal separator
(5 answers)
Closed 7 years ago.
I have random number for example: 85769038
And need to receive 85,769,038
need to put coma like in calculator to split every 3rd number from back
Please wright a full code for these case with first string with numbers 85769038 and ending NSLog to receive in console 85,769,038
This method must be universal for any quantity of numbers
You can use the NSNumberFormatter
NSNumberFormatter *f = [NSNumberFormatter new];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSString *ft = [f stringFromNumber:[NSNumber numberWithInteger:85769038]];
[ft release];

Best way to convert NSString into a number [duplicate]

This question already has answers here:
Convert string to float in Objective-C
(2 answers)
Closed 8 years ago.
I am building a calculator, and I have the following:
firstOperand = #"2883"
secondOperand = #"10"
operator = #"/" // division
How would I get the result here as an NSString? Here is how I would do the equivalent in Python:
result = str (float(firstOperand) / float(secondOperand))
How would I do the same in Obj-C?
Yo have two ways to do so.
If your string only contains the number and you are certain it is "well-written" you can just use
int i = [yourString intValue];
or floatValue, or doubleValue or integerValue ...
If your string is not well formatted, and you need something more powerful to extract the data, you need to use [NSNumberFormatter][1]. For instance:
NSNumberFormatter* formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber* number = [formatter numberFromString:yourString];
Code is ARC.
Instances of NSNumberFormatter format the textual representation of
cells that contain NSNumber objects and convert textual
representations of numeric values into NSNumber objects. The
representation encompasses integers, floats, and doubles; floats and
doubles can be formatted to a specified decimal position.
NSNumberFormatter objects can also impose ranges on the numeric values
cells can accept.

NSNumberFormatter w/ currency and NSDecimalNumber; $9.95 == 9.949999999999999 [duplicate]

I have some string s that is locale specific (eg, 0.01 or 0,01). I want to convert this string to a NSDecimalNumber. From the examples I've seen thus far on the interwebs, this is accomplished by using an NSNumberFormatter a la:
NSString *s = #"0.07";
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[formatter setGeneratesDecimalNumbers:YES];
NSDecimalNumber *decimalNumber = [formatter numberFromString:s];
NSLog([decimalNumber stringValue]); // prints 0.07000000000000001
I'm using 10.4 mode (in addition to being recommended per the documentation, it is also the only mode available on the iPhone) but indicating to the formatter that I want to generate decimal numbers. Note that I've simplified my example (I'm actually dealing with currency strings). However, I'm obviously doing something wrong for it to return a value that illustrates the imprecision of floating point numbers.
What is the correct method to convert a locale specific number string to an NSDecimalNumber?
Edit: Note that my example is for simplicity. The question I'm asking also should relate to when you need to take a locale specific currency string and convert it to an NSDecimalNumber. Additionally, this can be expanded to a locale specific percentage string and convert it to a NSDecimalNumber.
Years later:
+(NSDecimalNumber *)decimalNumberWithString:(NSString *)numericString in NSDecimalNumber.
Based on Boaz Stuller's answer, I logged a bug to Apple for this issue. Until that is resolved, here are the workarounds I've decided upon as being the best approach to take. These workarounds simply rely upon rounding the decimal number to the appropriate precision, which is a simple approach that can supplement your existing code (rather than switching from formatters to scanners).
General Numbers
Essentially, I'm just rounding the number based on rules that make sense for my situation. So, YMMV depending on the precision you support.
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[formatter setGeneratesDecimalNumbers:TRUE];
NSString *s = #"0.07";
// Create your desired rounding behavior that is appropriate for your situation
NSDecimalNumberHandler *roundingBehavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain scale:2 raiseOnExactness:FALSE raiseOnOverflow:TRUE raiseOnUnderflow:TRUE raiseOnDivideByZero:TRUE];
NSDecimalNumber *decimalNumber = [formatter numberFromString:s];
NSDecimalNumber *roundedDecimalNumber = [decimalNumber decimalNumberByRoundingAccordingToBehavior:roundingBehavior];
NSLog([decimalNumber stringValue]); // prints 0.07000000000000001
NSLog([roundedDecimalNumber stringValue]); // prints 0.07
Currencies
Handling currencies (which is the actual problem I'm trying to solve) is just a slight variation on handling general numbers. The key is that the scale of the rounding behavior is determined by the maximum fractional digits used by the locale's currency.
NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init];
[currencyFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[currencyFormatter setGeneratesDecimalNumbers:TRUE];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
// Here is the key: use the maximum fractional digits of the currency as the scale
int currencyScale = [currencyFormatter maximumFractionDigits];
NSDecimalNumberHandler *roundingBehavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain scale:currencyScale raiseOnExactness:FALSE raiseOnOverflow:TRUE raiseOnUnderflow:TRUE raiseOnDivideByZero:TRUE];
// image s is some locale specific currency string (eg, $0.07 or €0.07)
NSDecimalNumber *decimalNumber = (NSDecimalNumber*)[currencyFormatter numberFromString:s];
NSDecimalNumber *roundedDecimalNumber = [decimalNumber decimalNumberByRoundingAccordingToBehavior:roundingBehavior];
NSLog([decimalNumber stringValue]); // prints 0.07000000000000001
NSLog([roundedDecimalNumber stringValue]); // prints 0.07
This seems to work:
NSString *s = #"0.07";
NSScanner* scanner = [NSScanner localizedScannerWithString:s];
NSDecimal decimal;
[scanner scanDecimal:&decimal];
NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithDecimal:decimal];
NSLog([decimalNumber stringValue]); // prints 0.07
Also, file a bug on this. That's definitely not the correct behavior you're seeing there.
Edit: Until Apple fixes this (and then every potential user updates to the fixed OSX version), you're probably going to have to roll your own parser using NSScanner or accept 'only' double accuracy for entered numbers. Unless you're planning to have the Pentagon budget in this app, I'd suggest the latter. Realistically, doubles are accurate to 14 decimal places, so at anything less than a trillion dollars, they'll be less than a penny off. I had to write my own date parsing routines based on NSDateFormatter for a project and I spent literally a month handling all the funny edge cases, (like how only Sweden has the day of week included in its long date).
See also Best way to store currency values in C++
The best way to handle currency is to use an integer value for the smallest unit of the currency, i.e. cents for dollars/euros, etc. You'll avoid any floating point related precision errors in your code.
With that in mind, the best way to parse strings containing a currency value is to do it manually (with a configurable decimal point character). Split the string at the decimal point, and parse both the first and second part as integer values. Then use construct your combined value from those.

Where to store strings for iOS app [duplicate]

This question already has answers here:
Constants in Objective-C
(14 answers)
Closed 8 years ago.
I have an iOS app that requires me to have a "bank" of multiple strings. What I mean is that I need to have several strings that I can call upon at any time. Here is what I am thinking of.
// Strings.h
#define STR_ONE #"1"
#define STR_TWO #"2"
// ...
And when I need to use these strings, I simply include the header file. I chose to go with a header file because there will be many of these strings, and I just wanted to keep them separate.
So the question: Is this the best approach to solve my problem? Are there any alternate (and better) ways that I am missing?
Side notes: Is there any memory management I need to be thinking about here?
Should this be written to a file, and drawn upon from there?
Thankyou
NSArray: you can store a fixed amount of string insiden an array
NSArray* nameArr = [NSArray arrayWithObjects: #"Jill Valentine", #"Peter Griffin", #"Meg Griffin"
NSMutableArray: this type of array can expand and decrease in size.
NSMutableArray *names = [[NSMutableArray alloc] init];
[self.names addObject:#"Harry Potter"];
If the amount of Strings is not enorm, a simple Plist will work for you. But i also would recommend you to read about core data.
Property List Link

NSNumberFormatter, NSDecimalNumber and Scientific Notation

I'm having a serious dispute with NSNumberFormatter, and even after going through its extensive documentation, I haven't quite been able to wrap my head around a pretty straightforward issue that I encountered. I hope you guys can help me out.
What I have: an NSDecimalNumber representing a calculation result, displayed in a UITextField
What I need: Scientific notation of that result.
What I'm doing:
-(void)setScientificNotationForTextField:(UITextField*)tf Text:(NSString*)text {
NSString* textBefore = text;
// use scientific notation, i.e. NSNumberFormatterScientificStyle
NSNumberFormatter* formatter = [[NSNumberFormatter alloc] init];
//[formatter setGeneratesDecimalNumbers:YES];
[formatter setNumberStyle:NSNumberFormatterScientificStyle];
NSDecimalNumber* number = (NSDecimalNumber*)[formatter numberFromString:text];
tf.text = [number descriptionWithLocale:[[Utilities sharedUtilities] USLocale]];
NSString* textAfter = tf.text;
// DEBUG
NSLog(#"setScientificNotation | text before = %#, text after = %#", textBefore, textAfter);
[formatter release];
}
What happens:
A certain result may be 0.0099. textBefore will hold that correct value. If I don't tell the formatter to generate decimal numbers (commented out in the above snippet), it will create an NSNumber from an NSDecimalNumber which creates a false result and turns textAfterinto 0.009900000000000001 - a rounding error due to the reduced precision of NSNumber over NSDecimalNumber.
If I do tell the NumberFormatter to generate decimals, it will still create the wrong result . And what's more, where before it would insert the exponent notation (e.g. "1.23456e-10"), it would now generate (and thus display) the full decimal number, which is not what I want.
Again, I'd like to have the formatter use NSDecimalNumber so it doesn't falsify results plus have exponent notation where necessary.
Am I using the class wrong? Did I misinterpret the documentation? Can someone explain why this happens and how I can create the behavior I want? I will of course continue researching and update if I find anything.
You can't just cast an NSNumber to an NSDecimalNumber and expect it to work. If your number is not too complex, you can ditch NSNumberFormatter and try using this instead:
NSDecimalNumber* number = [NSDecimalNumber decimalNumberWithString:text];
That will give you an actual NSDecimalNumber instance, with its precision.
Unfortunately, setGeneratesDecimalNumbers: doesn't work properly. It's a known bug.
If your number is too complex to work with decimalNumberWithString:, you're probably out of luck with Apple's APIs. Your only options are either parsing the string manually into something NSDecimalNumber can understand or performing some post-processing on the imprecise value given to you by NSNumberFormatter.
Finally, if you really want a number in scientific notation, why not just use the number formatter you just used? Just call stringFromNumber: to get the formatted value.