Search code examples
objective-cxcodemacoscocoatrialware

Track real usage time in Cocoa app


Inspired by @PeterHosey's interesting comment in this question, I decided to implement usage time tracking system.

Like:

  • The app starts, the counter starts
  • The app terminates, the whole duration is logged
  • At any point (even during execution), that the total usage time exceeds the allowed time, the user receives a notification

However, I'm having a couple of... conceptual issues:

  • What am I going to track? Would [NSDate date] suffice?
  • What if the user simply changes his system date/time at some point?
  • Also, which specific delegate methods are to be hooked? I mean, where would you call the start/stop routines for the counting functions?

I'm all ears! :-)


Solution

  • Well, I don't think you need to use [NSDate date] approach for this. Why don't you use mach_absolute_time() function? To track the time elapsed, it may be some timer (ticks, for example, each minute).

    GCD-timers is a simple flexible way to implement timers, which you may suspend and resume if need (for example, if you want to suspend it while the program is not in use.).

    - (void)createTimerSource
    {
      // myTimerQueue and trialTimer are class members
      myTimerQueue = dispatch_queue_create("label.yourapp.com", NULL);
      trialTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, myTimerQueue);
      dispatch_source_set_timer(m_ping_timer, dispatch_time(DISPATCH_TIME_NOW,TimerPeriod * NSEC_PER_MSEC), TimerPeriod * NSEC_PER_MSEC,NSEC_PER_SEC/10);
      // set event handler
      dispatch_source_set_event_handler(m_ping_timer,^{
          // the code to check time elapsed
       });
      // set the cancel handler 
      dispatch_source_set_cancel_handler(m_ping_timer,^{
          // release timer dispatch source
          if(trialTimer)
             dispatch_release(trialTimer);
          // release dispatch timer
          if(myTimerQueue)
             dispatch_release(myTimerQueue);
       });
      // created sources always suspended
      dispatch_resume(trialTimer); // to suspend the timer use dispatch_suspend(trialTimer)
    }