NSTextField: integerValue behaving inconsistently - objective-c

I have found that [NSTextField integerValue] behaves differently with values containing thousands separators depending on how the value was set.
(I am in Germany, so my thousands separator in these examples is a point ".").
If I call [myTextField setIntegerValue:4567], the text field will contain 4.567 (with tousands separator), and [myTextField integerValue] returns 4567.
If I type the value 4.567 info the text field manually, or use [myTextField setStringValue:#"4.567"], then [myTextField integerValue] returns just 4.
Apparently it stops parsing the number at the thousands separator, even though it inserts such a separator itself when calling setIntegerValue.
So I have actually two questions:
Is there a setting or other easy way that I can prevent it to format the number when using -setIntegerValue: ?
Can I "enable" the number parsing to understand/accept thousands separators when calling -integerValue? Or, if not, what would be the simplest way to parse a number with thousands separator from an NSString?

Add a Number Formatter (NSNumberFormatter) to the text field in the storyboard or XIB. This makes the contents of the cell and objectValue of the text field a NSNumber instead of a NSString.
Is there a setting or other easy way that I can prevent it to format the number when using -setIntegerValue: ?
Switch off Grouping Separator of the formatter.
Can I "enable" the number parsing to understand/accept thousands separators when calling -integerValue?
Switch on Grouping Separator of the formatter and set Primary Grouping to 3.
Or, if not, what would be the simplest way to parse a number with thousands separator from an NSString?
Use a NSNumberFormatter, see the class reference and Number Formatters.

integerValue is not locale-aware, it will always use . as the decimal point.
You should use NSNumberFormatter.numberFromString: instead.
Link to NSNumberFormatter class reference.

Related

Prevent NSTextField from inserting commas when setting intValue

In my app I have an NSTextField into which the user can type a value for "Year". This works fine and I save the value off to a file as an integer. However, when I read this value back and place it back into the text field for editing, like so:
YearTextField.intValue = dataFromFile.year;
The year is comma separated, so an original value of 2020 appears as: 2,020
I know I can stringWithFormat the value into an NSString and then set the stringValue of the NSTextField, but is there a more straightforward way to simply tell YearTextField to not insert commas when setting the value?
Thanks!

how to insert extra glyphs?

I want to an UITextView to switch between two display modes.
In mode 1 it should show abbreviations and in the full word in mode 2. For example "Abbr." vs "abbreviation".
What would be the best way to do this? Keeping in mind that some words can have the same abbreviation and that the user is free to type either the full word or the abbreviation?
So far I tried to subclass NSLayoutManager.
Assuming I get an abbreviated string and I have to draw the full word, I would implement the following method:
-(void)setGlyphs:(const CGGlyph *)glyphs
properties:(const NSGlyphProperty *)props
characterIndexes:(const NSUInteger *)charIndexes
font:(UIFont *)aFont
forGlyphRange:(NSRange)glyphRange
{
NSUInteger length = glyphRange.length;
NSString *sourceString = #"a very long string as a source of characters for substitution"; //temp.
unichar *characters = malloc(sizeof(unichar) * length+4);
CGGlyph *subGlyphs = malloc(sizeof(CGGlyph) * length+4);
[sourceString getCharacters:characters
range:NSMakeRange(0, length+4)];
CTFontGetGlyphsForCharacters((__bridge CTFontRef)(aFont),
characters,
subGlyphs,
length+4);
[super setGlyphs:subGlyphs
properties:props
characterIndexes:charIndexes
font:aFont
forGlyphRange:NSMakeRange(glyphRange.location, length+4)];
}
However this method complains about invalid glyph indices "_NSGlyphTreeInsertGlyphs invalid char index" when I try to insert 4 additional glyphs.
You're barking way up the wrong tree; trying to subclass NSLayoutManager in this situation is overkill. Your problem is merely one of swapping text stretches (replace abbrev by original or original by abbrev), so just do that - in the text, the underlying NSMutableAttributedString being displayed.
You say in a comment "some words map to the same abbreviation". No problem. Assuming you know the original word (the problem would not be solvable if you did not), store that original word as part of the NSMutableAttributedString, i.e. as an attribute in the place where the word is. Thus, when you substitute the abbreviation, the attribute remains, and thus the original word is retained, ready for you when you need to switch it back.
For example, given this string: #"I love New York" You can hide the word "New York" as an attribute in the same stretch of text occupied by "New York":
[attributedString addAttribute:#"realword" value:#"New York" range:NSMakeRange(7,8)];
Now you can set that range's text to #"NY" but the attribute remains, and you can consult it when the time comes to switch the text back to the unabbreviated form.
(I have drawn out this answer at some length because many people are unaware that you are allowed to define your own arbitrary NSAttributedString attributes. It's an incredibly useful thing to do.)

Turning plain text into NSString

I have a list of words like: hello hi bonjour etc.
I'm literally adding #"" around every word manually. It's not bad, but when you have thousands of words it can get really tedious. Is there a method, where you input a bunch plain text like hello hi and it turns it into: #"hello" #"hi", which I can then copy into code, or do I have to do this manually?
the
be
and
of
a
What I've done in similar cases is use an editor's text replacement feature to replace all blanks with (in your case) " #". You may have to get a bit fancier if you don't have blanks at the start and end of each line, or you have multiple adjacent blanks, etc, but the general technique works.
It sounds like what you want is NSString's componentsSeparatedByString: method. You can enter in a bunch of plain text into some text field or text view, get the raw string, and then push that through "componentsSeparatedByString:#" "" (make sure there's one space in there) and out comes an array of words.
You could try loading the strings from a Plist -- inserting them into code is kind of ugly. Something like [NSDictionary dictionaryWithContentsOfURL:urlToMyPlist] or [NSArray arrayWithContentsOfURL:urlToMyPlist]
Look at the docs for NSString and you'll find the -initWithCharacters:length: method, which you can use to create strings. If you have a string that you want to break up into smaller strings, use -componentsSeparatedByString:.

NSNumberFormatter interfering with NSString intValue

I have an NSForm that is being used to display content to the user. The form can either be updated via the application by connecting to an web hosted XML file or manually edited by the user. Through Interface Builder I have set each form value to be formatted through an NSNumberFormatter to make the display of the data easier to read. The NSNumberFormatter is only inserting the thousands separator.
Because the data can be manually edited by the user, I am extracting the stringValue of the NSForm fields. I have noticed that when I perform this function, it also grabs the commas that have been injected into the string. I need to do some math with these values and it's causing a problem when trying to call NSString intValue or NSString floatValue. Anyone have any ideas?
I was thinking that I might have to "pre-parse" the string to remove the commas before converting it to a float or int value.
NSNumberFormatter can work backwards too:
NSNumber *n = [formatter numberFromString:#"123,456.78"];
float x = [n floatValue];

Construct a dynamic formatting string, for fixed width float values

I have a class holding various types of numeric values. Within this class I have a couple of helper methods that are used to output descriptor text for display within my application.
This descriptor text should always appear as an integer or float, depending on the definition of the particular instance.
The class has a property, DecimalWidth, that I use to determine how many decimals to display. I need help writing a line of code that displays the numeric value, but with a fixed number of decimals, (0 is a possibility, and in such a case the value should be displayed as an integer.)
I am aware that I can could return a value like [NSString stringWithFormat:#"%.02f", self.Value] but my problem is that I need to replace the '2' in the format string with the value of DecimalWidth.
I can think of couple ways of solving this problem. I could concat a string together and that is as the format string for the outputted string line. Or, I could make a format string within a format string.
These solutions sound hideous and seem rather inefficient, but maybe these are the best options that I have.
Is there an elegant way of constructing a dynamic formatting string where the output is a fixed decimal width number but the specified decimal width is dynamic?
That doesn't sound hideous or inefficient to me.
[NSString stringWithFormat:[NSString stringWithFormat:#"%%.%df", DecimalWidth], self.Value]
In fact I think it is rather elegant.
However one solution for the problem is definitely question suggested by #lulius caesar,
But one good way is also using NSNumberFormatter. Below is a sample code you can use to generate decimal values with fixed decimal number
NSNumberFormatter *numberFormatter=[[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numberFormatter setMinimumFractionDigits:DecimalWidth];
[numberFormatter setMaximumFractionDigits:DecimalWidth];
NSString * decimalString = [numberFormatter stringFromNumber:[NSNumber numberWithFloat:self.value]]]