Search code examples
iphoneobjective-ciosnstimerkey-value-observing

Key-Value-Observing and NSTimer


I'm trying to observe an int property (totalSeconds) in a class (StopWatch) where total seconds is incremented by one every time the time fires (one second intervals) my custom class (DynamicLabel) a subclass of UILabel should receive a observeValueForKeyPath message every time the totalSeconds changes but it is never called. Here is the relevant code:

#import "StopWatch.h"
@interface StopWatch ()

@property (nonatomic, strong) NSTimer *timer;

@end

@implementation StopWatch
@synthesize timer;
@synthesize totalSeconds;

- (id)init
{
    self = [super init];
    if (self) {
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(fireAction:) userInfo:nil repeats:YES];
        [runLoop addTimer:timer forMode:NSRunLoopCommonModes];
        [runLoop addTimer:timer forMode:UITrackingRunLoopMode];
    }
    return self;
}    

- (void)fireAction:(NSTimer *)aTimer
{
    totalSeconds++;
}

@end
#import "DynamicLabel.h"

@implementation DynamicLabel

@synthesize seconds;

- (void)observeValueForKeyPath:(NSString *)keyPath
                  ofObject:(id)object
                    change:(NSDictionary *)change
                   context:(void *)context
{
    seconds ++;
    [self setText:[NSString stringWithFormat:@"%i",seconds]];
}


@end

and in the view controller:

- (void)viewDidLoad
{
    [super viewDidLoad];
    watch = [[StopWatch alloc] init];
    [watch addObserver:dLabel1 forKeyPath:@"totalSeconds" options:NSKeyValueObservingOptionNew context:NULL];
}

where dLabel is an instance of DynamicLabel

Does anybody know why this is happening? It definitely has something to do with the NSTimer because I have tried this same thing where I change the value of totalSeconds manually to check if the KVO is working, and that works fine. However, when totalSeconds gets incremented in the timer's fire method, the observeValueForKeyPath method never gets called. Also, for those who are wondering why I am using KVO for this, it is because in the real app (this is just a test application), I need to display multiple running stopwatches (at different times) on the screen and record the elapsed times. I'd like to do this using one clock. I'd really appreciate any help I can get.

Thanks,


Solution

  • Key-Value Observing only works on properties. Your timer is not using your property accessor to increment the value; it's changing the ivar directly, which will not generate any KVO events. Change it to self.totalSeconds++, and it should work.