0

I made a class, called Timer. Its designated initializer starts a timer with a value in seconds. It works great. However I am having trouble updating the controller w/e the timer ticks.

Right now, for every tick I am sending a NSNotificationCenter with a userInfo that is a simple dictionary with the current time, which does not sound the best way to do it...

NSDictionary *dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:self.timerCount] forKey:@"timerCount"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"TimerCountChanged"
                                                    object:self
                                                  userInfo:dict];

Should I be using some other technique or am I doing it the right way?

Thank you in advance!

EDIT: I need to initialize different Timers, using different values. I tried to use Delegates, but I only had one method in my controller to update the UI for all those Timers! Would it be bad if I do something like? Passing a UIButton to my Model also does not seem to be the best solution but it works.

-(void)timer:(Timer *)timer didTriggerAt:(NSTimeInterval)time andButton:(UIButton *)button
{
        [button setTitle:[NSString stringWithFormat:@"%.0f", time] forState:UIControlStateNormal];
}

- (IBAction)startCountDown:(UIButton *)sender
{    
    self.timer1 = [[Timer alloc] initWithTimeInSeconds:10 andButton:sender];
    self.timer1.delegate = self;
}

I have 3 Timers in my MainView, the user can start them whenever he wants. They can also have different times, which is also defined by the user.

Marcelo
  • 1,176
  • 1
  • 10
  • 29
  • 1
    This is a good first step. Now you need to observe that notification using `NSNotificationCenter`'s addObserver:selector:name:object – Scott Berrevoets Mar 02 '13 at 03:49
  • Yea I did that, I just didn't know if using the NSNotificationCenter would be the best approach – Marcelo Mar 02 '13 at 04:14
  • Generally, `NSNotificationCenter` is a great way to deliver messages across your app without creating many dependencies. In this case however I would also suggest you look at protocols, as suggested in answers. Can you update the question with what exactly you are trying to do? Maybe there is an even better solution to this than creating multiple timers. – Pascal Mar 02 '13 at 04:57

2 Answers2

2

Sending Notifications is good, but you may not observe it as in regular time.

Sometimes it gets delayed and you may observe them in irregular time interval.

You can use

  1. Delegate Pattern.

  2. Call method by selector

EDIT:

From

Apple documentation on Performance CodeSpeed on Notifications.

The fewer notifications you send, the smaller the impact on your application’s performance. Depending on the implementation, the cost to dispatch a single notification could be very high. For example, in the case of Core Foundation and Cocoa notifications, the code that posts a notification must wait until all observers finish processing the notification. If there are numerous observers, or each performs a significant amount of work, the delay could be significant.

Anoop Vaidya
  • 46,283
  • 15
  • 111
  • 140
  • 2
    I wrote a rather lengthy answer to another post about setting up delegates. Feel free to check it out if it is helpful: http://stackoverflow.com/questions/10272843/back-button-in-iphone-app/10273551#10273551 – JiuJitsuCoder Mar 02 '13 at 03:54
  • The problem I had with Delegates is that I am initializing different Timers at different times, but I am only going to have one event in my controller to update my UI. – Marcelo Mar 02 '13 at 04:47
  • 2
    Are you sure about the `NSNotification` delay? I use notifications very frequently and never saw this problem, the notifications are even delivered in the same run-loop. – Pascal Mar 02 '13 at 04:54
  • @Pascal: http://www.cocoabuilder.com/archive/cocoa/309839-nsarraycontroller-update-delay.html, Also see my edit. – Anoop Vaidya Mar 02 '13 at 06:10
  • 1
    @AnoopVaidya Your words, to me, mean that you are saying that it's asynchronous, that program execution will continue for some time before all observers see posted notifications. Your cocoabuilder link discusses a particular class's implementation of notifying KVO observers (not relevant to NSNotification), and the Apple docs point out that posting a notification can be expensive, but indicate that it is synchronous. Could you clarify what your concerns are a bit more? – Carl Veazey Mar 02 '13 at 21:06
  • @AnoopVaidya Your link discusses a different problem with KVO. Apple's documentation highlights a different problem as well, namely that notifications **are** synchronous and therefore, when you post a notification, all observers must finish processing the notification before your run loop ends. This means as long as you keep in mind not to do too much work on notifications, there is no problem. – Pascal Mar 02 '13 at 22:20
0

If you only have one client object for each Timer instance, then you should use the delegate pattern. You would define a TimerDelegate protocol with a method that a Timer object can call whenever the timer ticks.

e.g.

@class Timer;

@protocol TimerDelegate
- (void) timer:(Timer *)timer didTriggerAt:(NSTimeInterval)time;
@end

@interface Timer
...
@property (assign) id<TimerDelegate> delegate;
...
@end

If you indeed require multiple listeners each time a Timer instance ticks, then the NSNotificationCenter approach would be a better fit. Instead of passing info in the userInfo dictionary, I probably would expose an @property on Timer called currentTime, so that when a client object gets the notification, they could simply access currentTime on the notifying Timer, instead of (IMO clunkily) reading data out of userInfo.

tom
  • 18,953
  • 4
  • 35
  • 35