0

This is probably an easy question, but I'm a newbie, so I'm drawing a blank.

I have a 2D graphical application whose graphics (implemented in drawRect) depend upon the date. When the date changes, the graphics change, so I figure I need to call

[myView setNeedsDisplay: YES];

when the date changes. I've seen code for timers, but this doesn't seem to be a timer type of scenario. How would I check if the local date has changed, and what class would I put that code in? I assume it would go in the .m file for my main view.

Besides automatically triggering upon a change of date, eventually, the app will need to trigger upon user input (perhaps a button to go forward or backward one day or upon a date picker selection).

The graphics render just fine as is, but I've not coded any date trigger, so while the drawRect code is date specific, it doesn't change when the date changes.

P.S. My basic question, above, has been answered, but now that I go to implement it, I realize I have another issue. I ought to have a property somewhere to track the date whose configuration is currently being displayed. The obvious idea is to add a property to the main view holding an NSDate object. But the way I've coded things, the calculations are done by a method in a subview class. So the question is, how to update the NSDate property of the main view from the subview. An alternative would be to add an NSDate property to the subview, but there are multiple such subviews, and that would seem to be redundant. Any opinion on this?

Victor Engel
  • 2,037
  • 2
  • 25
  • 46
  • I have not tried anything. I need to have an idea first before trying something, and for some reason I'm drawing a blank. I'll look into NSDate and related items. Thanks. – Victor Engel Jul 06 '12 at 20:16
  • Also, you should be more specific about what kind of date change you want - day, year, month, minute, second? NSDate will register all of those changes, and it's up to you to isolate the change you want. – Dustin Jul 06 '12 at 20:20
  • Dustin, does it really change the answer if the type of date change is different? In any case, without more specifics, a date is simply a name for a day. Dates change daily. The event I hope to tap into is a daily event. It need not be, in general, though. The default situation will probably be triggered by local midnight, but again, it need not be. For testing, I'll probably use a minute trigger, for example. – Victor Engel Jul 06 '12 at 21:14

1 Answers1

2

You can use an NSTimer for this. First, though, you need to figure out when that NSTimer should fire. You can use NSDate, NSCalendar, and NSDateComponents for that:

NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *todayComponents = [calendar components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit fromDate:[NSDate date]];
NSDate *today = [calendar dateFromComponents:todayComponents];
// today is the start of today in the local time zone.  Note that `NSLog`
// will print it in UTC, so it will only print as midnight if your local
// time zone is UTC.

NSDateComponents *oneDay = [[NSDateComponents alloc] init];
oneDay.day = 1;
NSDate *tomorrow = [calendar dateByAddingComponents:oneDay toDate:today options:0];

Once you have tomorrow, you can set a timer to fire on that date:

NSTimer *timer = [[NSTimer alloc] initWithFireDate:tomorrow interval:0 target:self selector:@selector(tomorrowTimerDidFire:) userInfo:nil repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
// The run loop retains timer, so you don't need to.

And in tomorrowTimerDidFire::

- (void)tomorrowTimerDidFire:(NSTimer *)timer {
    [myView setNeedsDisplay:YES];
}
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • Thanks so much for the thorough reply. – Victor Engel Jul 06 '12 at 21:16
  • I forgot to mention that you will probably want to create another timer in `tomorrowTimerDidFire:`, because when `tomorrowTimerDidFire:` runs, the old tomorrow is now today and you need to call it again on the new tomorrow. – rob mayoff Jul 06 '12 at 21:18
  • Thanks, Rob. That's what I assumed, but good idea to have mentioned it. This brings up another question. In my reading on timers, I saw mention of killing the timer when finished. Care to comment on that? – Victor Engel Jul 06 '12 at 21:44
  • A non-repeating timer automatically invalidates itself. You don't need to do any other cleanup. – rob mayoff Jul 06 '12 at 21:45
  • Good. Now that I sit down to work on this, I realize I have another issue. But maybe it needs its own question. I really should be storing the date somewhere. I'm thinking the main view would be the best place, but the date calculations are actually done in a subview. Can I set a date property in the main view from a subview? I could set a property in a subview, but there are many, and that seems redundant. I'd be more specific, but I'm running out of characters. – Victor Engel Jul 06 '12 at 22:12
  • It sounds like you might be better off having some other object (a controller or model object, or the app delegate) doing the timer, and posting a custom notification when the timer fires. All the views that care about the date change can observe the notification and redraw themselves. Look at `NSNotificationCenter` and `NSNotification`. – rob mayoff Jul 06 '12 at 22:15
  • I have read about NSNotificationCenter but have not used it yet. Sounds like good practice for me even if what I was doing would also work. Thanks for the suggestion. BTW, I added a P.S. to my original question to describe the situation in more detail. – Victor Engel Jul 06 '12 at 22:27
  • Hmmm. I think I will do something else. This answer assumes a calendar. I'm not interested in the calendar in effect. I'm only interested in local midnight. Depending on the calendar, the day could change at a time other than midnight, and I don't want that. – Victor Engel Jul 14 '12 at 19:20
  • One more comment: your code, above, doesn't take DST into account, right? – Victor Engel Jul 23 '12 at 06:44
  • I believe it does. You should test it by figuring out when DST begins or ends and passing that to `components:fromDate:`. – rob mayoff Jul 23 '12 at 07:21
  • I asked because I'm actually getting a transition at 1AM. For my application, this is fine, but that will not always be true. BTW, how were you able to notice an update in the thread so quickly? Is there an option somewhere where I can be notified of an update? – Victor Engel Jul 23 '12 at 15:10
  • I just happened to be viewing the site and saw the red notification circle at the top left. – rob mayoff Jul 23 '12 at 16:34