【问题标题】:Find out last fired UILocalNotification找出最后触发的 UILocalNotification
【发布时间】:2014-07-30 01:27:52
【问题描述】:

我正在开发一个使用 UILocalNotifications 的 iOS 警报应用程序。到目前为止一切顺利,直到有人提出了显示从用户所在位置到他想去的地方的路线的想法。

为此,我想我可能会得到最后一次触发的 UILocalNotification(它们都将 repeatInterval 设置为每周或每天)。

这就是问题所在,因为 fireDate 是我第一次安排它们:这是我的场景:

        UILocalNotification* ln = [[UILocalNotification alloc] init];
        ln.fireDate = date; // For instance 07/19/2014 10:00:00 (Saturday)
        ln.repeatInterval = NSDayCalendarUnit;            
        [[UIApplication sharedApplication] scheduleLocalNotification:ln];

        UILocalNotification* ln = [[UILocalNotification alloc] init];
        ln.fireDate = date; // For instance 07/17/2014 11:00:00 (Thursday)
        ln.repeatInterval = NSWeekCalendarUnit;            
        [[UIApplication sharedApplication] scheduleLocalNotification:ln];

让我们想象一下:

下周四(2014 年 7 月 24 日 11:00:01)我想知道最后一次触发的 UILocalNotification 是第二个,它只在星期四重复,第二天我想要第一个,因为它每天都重复。

我尝试按日期对所有 LocalNotifications 进行排序,但没有成功。

以前有没有人遇到过类似的情况?

问候

【问题讨论】:

    标签: ios date nsdate nsdatecomponents


    【解决方案1】:

    iOS 将在触发后丢弃本地通知,即使它计划通过repeatInterval 属性重复自身。

    [UIApplication sharedApplication].scheduledLocalNotifications 实际上会返回所有计划在未来触发的通知。 所以他们的fireDate 将被设置为未来的某个日期。

    经过进一步调查,似乎fireDate 始终设置为创建通知时指定的原始值。但是,下一个火灾日期(计算值)将在未来。要查看此值,只需在调试器中运行 po yourNotificationObj,您将看到以下类型的输出,其中包括下一个触发日期:

    {开火日期 = 七月星期六 2014 年 26 月 26 日下午 1:42:50 东部夏令时间,时区 = (null), 重复间隔 = NSMinuteCalendarUnit,重复计数 = UILocalNotificationInfiniteRepeatCount,下一个触发日期 = 星期六, 2014 年 7 月 26 日东部夏令时间下午 1:43:50,用户信息 = (null)}

    你如何计算下一个开火日期?请看以下代码取自How to grab the NEXT fire date from a UILocalNotification object

    NSCalendar *calendar = localNotif.repeatCalendar;
    if (!calendar) {
      calendar = [NSCalendar currentCalendar];
    }
    
    NSDateComponents *components = [[[NSDateComponents alloc] init] autorelease];
    // If you use some other repeat interval you would have to change the code accordingly. 
    // If you were to use NSMonthCalendarUnit you would have 
    // to use `components.month = 1' instead
    components.day = 1;
    NSDate *nextFireDate = [calendar dateByAddingComponents:components toDate:localnotif.fireDate options:0];
    

    如果您想记住上次触发的本地通知,则必须将该逻辑构建到您的应用中并保存所需的信息。例如,您可以执行以下操作:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        UILocalNotification *localNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
    
        if (localNotification) {
            [self saveLocalNotification:localNotification];
        }
    
        return YES;
    }
    
    - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
    {
        [self saveLocalNotification:notification];
    }
    
    - (void)saveLocalNotification:(UILocalNotification *)notification
    {
        // save information about the last fired local notification on disk
    }
    
    - (UILocalNotification *)lastFiredLocalNotification
    {
        // read the information stored on disk by the saveLocalNotification: method
        // and recreate the notification. I'm just saying recreate the notification
        // because I don't know what exactly you're trying to do. You 
        // can return anything you want here
    }
    

    使用上述设置,您可以在需要时调用lastFiredLocalNotification 方法。

    【讨论】:

      【解决方案2】:

      iOS 在本地通知被触发后会丢弃它们。如果您以后需要这些信息,您有责任以其他方式维护这些信息。

      如果需要,您可以检查 [UIApplication sharedApplication].scheduledLocalNotifications.firstObject 以查看已安排的下一个,然后使用该信息根据您自己的数据模型确定之前的数据。

      【讨论】:

      • 我已经检查过了,似乎 iOS 只丢弃了没有设置 repeatInterval 的通知。在我的场景中,所有本地通知都已设置,因为我可以在它们触发后列出所有通知。
      【解决方案3】:

      基于@Sid 的回答和 SO 中的一些代码 sn-ps,我可以提出这个解决方案,它可以计算所有本地通知的最后触发日期,而无需将其写入文件甚至数据库。 (虽然写在某个地方也不错)

      标题

      #import <UIKit/UIKit.h>
      
      @interface UILocalNotification (LastFireDate)
      
      - (NSDate *)lastFireDateBeforeDate:(NSDate *)afterDate;
      
      @end
      

      实施

      #import "UILocalNotification+LastFireDate.h"
      
      @implementation UILocalNotification (LastFireDate)
      
      - (NSDate *)lastFireDateBeforeDate:(NSDate *)afterDate
      {
          // Check if fire date is in the future:
          if ([afterDate compare:self.fireDate] == NSOrderedAscending)
              return [NSDate dateWithTimeIntervalSince1970:0];
      
          // The notification can have its own calendar, but the default is the current calendar:
          NSCalendar *cal = self.repeatCalendar;
          if (cal == nil)
              cal = [NSCalendar currentCalendar];
      
          // Number of repeat intervals between fire date and the reference date:
          NSDateComponents *difference = [cal components:self.repeatInterval
                                                fromDate:self.fireDate
                                                  toDate:afterDate
                                                 options:0];
      
          // Add this number of repeat intervals to the initial fire date:
          NSDate *lastFireDate = [cal dateByAddingComponents:difference
                                                      toDate:self.fireDate
                                                     options:0];
      
          // If necessary, subtract one interval:
          if ([lastFireDate compare:afterDate] == NSOrderedDescending) {
              switch (self.repeatInterval) {
                  case NSWeekCalendarUnit:
                      difference.week--;
                      break;
                  case NSDayCalendarUnit:
                      difference.day--;
                      break;
                  case NSHourCalendarUnit:
                      difference.hour--;
                      break;
                  default:
                      break;
              }
              lastFireDate = [cal dateByAddingComponents:difference
                                                  toDate:self.fireDate
                                                 options:0];
          }
          return lastFireDate;
      }
      
      
      @end
      

      用法

          NSDate* date = [NSDate date];
          NSArray* arrayNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
      
          if([arrayNotifications count])
          {
              NSArray *sorted = [arrayNotifications sortedArrayUsingComparator:^NSComparisonResult(UILocalNotification *obj1, UILocalNotification *obj2) {
                  NSDate *next1 = [obj1 lastFireDateBeforeDate:date];
                  NSDate *next2 = [obj2 lastFireDateBeforeDate:date];
                  return [next1 compare:next2];
              }];
      
              UILocalNotification* lastLocalNotification = [sorted lastObject];
              NSLog(@"%s %@",__PRETTY_FUNCTION__,[lastLocalNotification lastFireDateBeforeDate:date]);
          }
      

      希望对遇到同样问题的人有所帮助

      干杯

      【讨论】:

      • +1。感谢您发布您的解决方案。这对未来的访客真的很有帮助。
      • @PauloMiguelAlmeida 请您根据时区修改此代码,我在 UILocalNotification 中指定了 defaultTimeZone 并且我正在通过更改时区来计算日期,但我得到错误的结果,请帮助我根据修改您的代码默认时区。谢谢
      • @S.J 只要您在 UILocationNotification 和此类别方法上使用相同的时区,您使用的时区实际上并不重要。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多