- Let's say you have a NSTextField label.
- Let's say you have attached a formatter to the NSTextField.
- Let's say the formatter may not return the same string for the same object depending on the time of the day.
[Q] How do you force the refresh the string displayed by the NSTextField when you provide the same object value over time?
So far, I've only found an ugly solution: call setNeedsDisplay:YES when I set the object value.
I'm looking for a more elegant solution.
An example illustrating the "issue". The MainMenu.xib file contains a NSWindow with a NSTextField.
When the [_label setNeedsDisplay:YES]; line is uncommented, the displayed NSTextField string is refreshed every 5 seconds as expected. Otherwise, it's not.
#import "AppDelegate.h"
@interface MyFormatter : NSFormatter
@property NSUInteger counter;
@end
@implementation MyFormatter
- (nullable NSString *)editingStringForObjectValue:(id)inObject
{
if (inObject==nil)
return @"";
if ([inObject isKindOfClass:NSString.class])
return inObject;
if ([inObject isKindOfClass:NSAttributedString.class]==YES)
return ((NSAttributedString *)inObject).string;
return @"";
}
- (NSString *)stringForObjectValue:(id)inObject
{
if (inObject==nil)
return @"";
return [NSString stringWithFormat:@"%lu",(unsigned long)self.counter];
}
#pragma mark -
- (BOOL)getObjectValue:(id *) outObject forString:(NSString *) inString errorDescription:(out NSString **) outError
{
*outObject=[inString copy];
return YES;
}
@end
@interface AppDelegate ()
{
IBOutlet NSTextField * _label;
MyFormatter * _formatter;
NSTimer * _timer;
}
- (void)updateFormatter:(NSTimer *)inTimer;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
_formatter=[MyFormatter new];
_label.formatter=_formatter;
_label.objectValue=@"objectValue";
_timer=[NSTimer scheduledTimerWithTimeInterval:5
target:self
selector:@selector(updateFormatter:)
userInfo:nil
repeats:YES];
}
- (void)updateFormatter:(NSTimer *)inTimer;
{
_formatter.counter++;
_label.objectValue=@"objectValue";
//[_label setNeedsDisplay:YES];
}
@end