How do you refresh the string displayed by a NSTextField?

  • 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
  • I'm looking for a more elegant solution. Can you clarify what you think is more elegant? What I can think of first is setNeedsDisplay:YES and it is quite elegant for me.

  • What's the problem with setNeedsDisplay ? It is exactly intended for this, to update display and keep you in control. I find it really convenient and clean. Note that you don't change the content (update would be automatic) but you ask for changing the way content is displayed.

Add a Comment