Display an empty field when NSTextField contents are 0 - cocoa

I have an NSTextField which holds numeric (integer) values. There is a number formatter attached to the field. I want to display an empty field when the value of the field is set to 0 (zero). I think I tried every combination with the formatter, without luck so far. Can this be done?

I don't think you can do that with NSNumberFormatter. But you could make a subclass and implement stringFromNumber: something like this:
-(NSString *)stringFromNumber:(NSNumber *)number {
NSNumber *zero = [NSNumber numberWithInt:0];
if ([number isEqualToNumber:zero])
return #"";
else
return [super stringFromNumber:number];
}
EDIT:
I was wrong. You can do that with NSNumberFormatter:
[formatter setZeroSymbol:#""];

Related

Setting UILabel to Same value as NSString

I have searched for hours on this one subject and still have not been able to solve my problem. I have a string value that I need converted into a label. In my code I save the NSString and then make sure I am getting a value with the NSLog (which I DO). Then is where I am having problems. I try to set the label value equal to the nesting but when I run its NSLog I get (null). So my question is how may I make my label equal the value of my string? Thank you so much!
NSString *linkString = self.product[#"link"];
NSLog(#"%#", linkString);
linkLabel.text = linkString;
NSLog(#"%#", linkLabel);
Your NSString will never be equal to your UILabel.
on the other hand, your UILabel's text property which is an NSString will be
try to change the code to this
NSString *linkString = self.product[#"link"];
NSLog(#"%#", linkString);
linkLabel.text = linkString;
NSLog(#"%#", linkLabel.text);
All I changed was linkLabel in your NSLog to linkLabel.text
Assuming like you said that linkString has a value, the second log should output the same as the first log.
EDIT: I saw your comment above, there is no need for a duplicate definition of the label as an #property and above that in the h file.
Are you sure that
NSString *linkString = self.product[#"link"];
works? Try this:
NSString *linkString = #"Test";
and use this for logging:
NSLog(#"%#", linkLabel.text);
Did you forget to hook up the linkLabel in your XIB? Is the value of linkLabel not nil?
What does NSLog(#"%#", linkLabel); print out?

How to trim off symbols from NSNumber?

Im making an iOS app to do with currency. My app receives the value of maybe: $4. This value the app receives is put into an NSNumber. The trouble is the value actualy has a $ in it. How do I trim out the $ in the NSNumber? Or would I be better of putting it into an NSString?
Use NSNumberFormatter:
// set up your number formatter
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
// get a string that you'll be converting to a NSNumber
NSString *myNumberString = [NSString stringWithFormat:#"$4"]
// convert then print to the console
NSNumber *myNumber = [numberFormatter numberFromString:myNumberString];
NSLog(#"myNumber: %#", myNumber);
This should accomplish what you're looking to do. myNumberString will need to be altered to contain whatever string you're receiving.
NSNumberFormatter Documentation: https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSNumberFormatter_Class/Reference/Reference.html

Issues using NSNumberFormatter?

I'm trying to make a label to show the temperature, with a maximum of 3 digits for temperatures over a 100, but I don't want any decimals...
NSString *longtempstring = [tmp description];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:3];
[formatter setMinimumFractionDigits:0];
NSString *shorttempstring = [formatter stringForObjectValue:[NSString stringWithString:longtempstring]];
The code above always returns (null)
Any ideas?
You are getting nil because the object you are passing to stringForObjectValue: is not of the type expected.
First of all, don't use stringForObjectValue:. That is a member of the parent class, NSFormatter. NSNumberFormatter has more specific methods that avoid confusion of object types like numberFromString: and stringFromNumber:.
Second, NSNumberFormatter is used to go from number to formatted string or formatted string to number. Not directly from formatted string to formatted string. You will need to use one number formatter to read your original string and produce a number and another to produce a new shorter formatted string from that number.
Of course, you might be able to make the first step (from long string to number) easier by using NSScanner or by taking a substring of your long string (cutting out everything except for the number itself) and then using the NSString method integerValue or doubleValue. A regular expression could also be used to extract the number from the first (longer) string.
The long and short of it is, this is a two step process. The first step (getting a number) can be accomplished any number of ways and a NSNumberFormatter might not be the easiest way. The second step (getting a new shorter string) is what NSNumberFormatter is perfect for.
I fixed it by converting the NSString to an NSNumber and only pulling the integer value from the string, thus removing any decimals.
NSString *longtempstring = [tmp description];
NSNumber *tempintegervalue = [NSNumber numberWithInteger:[longtempstring integerValue]];
NSString *shorttempstring = [tempintegervalue stringValue];
NSString *longtempstring = [tmp description];
What is the value of longtempstring here? Is it even a number?
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:3];
[formatter setMinimumFractionDigits:0];
Why do you set maximum fraction digits to 3 if you say that you don't want any fraction digits? Fraction digits are what is "after the dot" and you say you don't want any decimals. If you don't want any decimals, minimum and maximum must be set to 0.
NSString *shorttempstring = [formatter stringForObjectValue:[NSString stringWithString:longtempstring]];
First of all, why are you copying the string? [NSString stringWithString:...] creates a new string that is a copy of the string you provide as argument. Strings are immutable, there is no need to copy them, they won't be modified. If you are afraid that a NSString may in fact be a NSMutableString, after all that is a subclass of NSString and you want to copy it, just copy it by calling [aString copy]. copy is a very smart method here. If the NSString is in fact a mutable string, it will really copy it, so you get an immutable copy. If it is not a mutable string, though, copy just returns the same string with a retain count increased by one (so in that case copy behaves exactly like retain). However, in your case copying makes no sense whatsoever.
And second, what makes you believe, that you can feed a string into a NSNumberFormater? It is called NSNumberFormater because it formats objects of type NSNumber. How is a NSString a NSNumber? It is not called NSStringFormater. If you feed an object of the wrong class to a formater, it will return nil, that's how this method is documented.
If your longtempstring contains a number with fraction, e.g. 12.345, then the correct code would look like this:
NSString * longtempstring = [tmp description];
NSNumberFormatter * formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:0];
[formatter setMinimumFractionDigits:0];
NSNumber * tempnumber = [NSNumber numberWithDouble:[longtempstring doubleValue]];
NSString * shorttempstring = [formatter stringForObjectValue:tempnumber];
However, if all you want to do is cut off the decimals, that is a horrible way to do it. This can be done much more effective:
double d;
NSString * longtempstring;
NSString * shorttempstring;
longtempstring = #"12.345";
d = [longtempstring doubleValue];
shorttempstring = [NSString stringWithFormat:#"%d", (int)d];
This is much shorter, needs less memory, and is at least three times faster. If you want to round the number (that means everything with a fraction .5 and above is rounded to the next higher value), just round it:
d = round([longtempstring doubleValue]);

NSNumberFormatter doesn't allow typing decimal numbers

I am totally bewildered using NSNumberFormatter. This should be totally simple but I can't get it to work.
I'd like to set an NSTextField to allow typing decimal numbers, either with a decimal point or without. Here is what I'd think would work:
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setMinimumFractionDigits:0];
[formatter setMaximumFractionDigits:4];
[formatter setAllowsFloats:YES];
[[timeFlowMultiplierTF cell] setFormatter:formatter];
However, when typing in the textfield, pressing the "period" key for the decimal point doesn't yield one. Typing "3.14" give me "314". Throwing in [formatter setAlwaysShowsDecimalSeparator:YES] will initially format the number correctly, but if I type over it, I once again cannot type the decimal point.
What am I missing here? You would think this would be really simple
I realize this is about 4 years too late, but I just ran into this same nonsense and thought I'd share what the problem is (or could be), for posterity.
It turns out that all of the value accessors of NSTextField (-objectValue, -stringValue, -doubleValue, and so on) all end up calling -validateEditing. -validateEditing, in turn, uses the attached NSFormatter to convert the edited text into an object value, and then resets the text in the field with the reformatted value.
So if you have any code that watches the field as the user edits it and you "peek" at the value in the field, you are inadvertently reformatting and resetting the text in the text field.
It's not that the text field won't let you type a period; it's that is the text field already has "3" in it and when you type a period the text changes to "3.". If you then have an action/notification/delegate method that runs whenever something in the field changes, and you call any of the -typeValue methods, the "3." get formatted as "3" and it updates the cell, erasing the period you just typed.
My hack was to avoid the -typeValue methods and peek into the NSText object to get the edited text directly, without triggering -validateEditing:
// some method that runs every time the field changes...
NSTextField* valueField = self.valueField;
NSNumberFormatter* fieldFormatter = valueField.formatter;
NSText* fieldEditor = valueField.currentEditor;
id newValue = ( fieldEditor!=nil ? [fieldFormatter numberFromString:fieldEditor.string] : valueField.objectValue );
Thanks to and following on from #James Bucanek's answer: here is a Swift implementation that I've used when I was over-riding controlTextDidChange delegation method which unblocked the user from typing a decimal point. It also updates the enabled flag of a button on the interface according to if there's a valid (i.e > zero and non-zero length string) entry:
override func controlTextDidChange(notification: NSNotification) {
if let formatter: NSNumberFormatter? = self.user_textfield.formatter as? NSNumberFormatter {
if let field_editor: NSText = self.user_textfield.currentEditor() {
if let new_value: Float? = formatter!.numberFromString(field_editor.string!)?.floatValue {
self.my_button_out.enabled = new_value > 0.0
} else {
self.my_button_out.enabled = false
}
}
}
}

NSTextView add URL link to the selected Text?

I Have an NSTextView.
I just want to add an Attribute (an NSLinkAttributeName) to the selected Text in the NSTextView...
Can You Help me ?
Thanks.
You want to get the view's textStorage (which is basically a mutable attributed string), then add the NSLinkAttributeName attribute to the selected range; the value of that attribute is the URL to link to.
[[textView textStorage] addAttribute: NSLinkAttributeName value: url range:[textView selectedRange]];
Been a while since I played with ObjC but this should do the trick. It replaces the selected text with the original content with your attr appended. Checked through it but please excuse any typos.
NSTextView *textView = ...;
NSDictionary *attributes = ...;
//Get selected text string from TextView (see Text superclass) and append attr link
NSRange selRange = [textView selectedRange];
NSMutableString *changedStr = [[[textView string] substringWithRange:selRange] mutableCopy];
[changedStr appendString:[attributes objectForKey:NSLinkAttributeName]];
//Replace the selected text range in the TextView
[textView replaceCharactersInRange:selRange withString:[NSString stringWithString:changedStr]];
[changedStr release];
See class defs:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSText_Class/Reference/Reference.html
-replaceCharactersInRange:withString:
-selectedRange
-scrollRangeToVisible: if you want to present your change immediately
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html
substringWithRange:

Resources