title: Stop Audio Player after X minutes
body: <p>I'm working on an Audio App. One task that I must accomplish is to be able to stop the audio player after X minutes (defined by user), like a player sleep.</p>
  
  <p>To do it, I use local notifications.</p>
  
  <p>This is the code in my custom player:</p>
  
  <pre><code>- (void)configureSleepTimer:(NSUInteger)seconds {
      UILocalNotification *localNotification = [[UILocalNotification alloc] init];
      localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:seconds];
      localNotification.timeZone = [NSTimeZone defaultTimeZone];
      localNotification.soundName = UILocalNotificationDefaultSoundName;
  
      NSDictionary *userInfo = [NSDictionary dictionaryWithObjects:@[@"PlayerSleep"] forKeys:@[@"type"]];
      localNotification.userInfo = userInfo;
  
      [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
      NSLog(@"Notification: %@", localNotification);
  }
  </code></pre>
  
  <p>AppDelegate:</p>
  
  <pre><code>- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
      if ([[notification.userInfo valueForKey:@"type"] isEqualToString:@"PlayerSleep"]) {
          Player *player = [Player sharedInstance];
          [player stopPlayer];
      }
  }
  </code></pre>
  
  <p>The problem with the above code, is that the player does not stops when the app is running in the background.</p>
  
  <p>To get this run in the background, I check when the app enters in background mode and check if exists local notifications. If exists, I fire a one second timer to compare notifications firetimes with real date to stop the player if needed.</p>
  
  <pre><code>- (void)applicationDidEnterBackground:(UIApplication *)application {
      __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
          [application endBackgroundTask:bgTask];
          bgTask = UIBackgroundTaskInvalid;
      }];
  
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
          if ([[[UIApplication sharedApplication] scheduledLocalNotifications] count]) {
              NSTimer *t = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(sleepPlayer) userInfo:nil repeats:YES];
              [[NSRunLoop currentRunLoop] addTimer:t forMode:NSDefaultRunLoopMode];
              [[NSRunLoop currentRunLoop] run];
          }
      });
  }
  
  - (void)sleepPlayer {
      [[[UIApplication sharedApplication] scheduledLocalNotifications] enumerateObjectsUsingBlock:^(UILocalNotification *notification, NSUInteger idx, BOOL *stop) {
          NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
          [formatter setDateFormat:@"dd-MM-yyyy HH:mm:ss"];
          NSString *dateTimeStr = [formatter stringFromDate:[NSDate date]];
          NSString *notifDateStr = [formatter stringFromDate:[NSDate dateWithTimeInterval:-1 sinceDate:notification.fireDate]];
  
          if ([dateTimeStr isEqualToString:notifDateStr]) {
              Player *player = [Player sharedInstance];
              [player stopPlayer];
              [[UIApplication sharedApplication] cancelLocalNotification:notification];
  
              NSLog(@"************************** Player Sleeped");
          }
      }];
  }
  </code></pre>
  
  <p>It works, but, I don't like this last piece of code. Is there a better way of doing it?</p>