如何实现每月重复本地通知排除指定日期?
解决每月重复通知排除指定日期的问题
你的每月重复通知实现已经很到位了,要排除某个特定日期不推送,最直接可靠的方法是利用UNUserNotificationCenter的代理方法在通知即将展示前进行拦截判断,下面是具体的实现步骤:
方法一:通过代理拦截通知展示
这种方法不需要修改原有的重复通知设置,只需要在通知触发时检查日期,符合排除条件就阻止展示。
1. 设置通知中心代理
首先确保你的类(比如AppDelegate或者专门的通知管理类)遵循UNUserNotificationCenterDelegate协议,并设置代理:
// 在合适的地方(比如AppDelegate的didFinishLaunchingWithOptions里)设置代理 UNUserNotificationCenter.current().delegate = self
2. 实现拦截方法
实现userNotificationCenter(_:willPresent:withCompletionHandler:)方法,在这个方法里判断当前触发的通知日期是否是你要排除的日期:
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { // 先获取通知的触发日期 guard let calendarTrigger = notification.request.trigger as? UNCalendarNotificationTrigger, let fireDate = Calendar.current.date(from: calendarTrigger.dateComponents) else { // 如果无法获取触发日期,正常展示通知 completionHandler([.alert, .sound]) return } // 定义你要排除的目标日期(这里以2018年5月28日为例) let excludedDate = Calendar.current.date(from: DateComponents(year: 2018, month: 5, day: 28))! // 判断触发日期是否和排除日期是同一天 if Calendar.current.isDate(fireDate, inSameDayAs: excludedDate) { // 不展示通知,传入空的展示选项 completionHandler([]) } else { // 正常展示通知,按需设置展示选项 completionHandler([.alert, .sound]) } }
扩展:支持排除多个日期
如果需要排除多个日期,只需要把排除日期放到数组里,用contains(where:)判断即可:
// 定义多个要排除的日期 let excludedDates: [Date] = [ Calendar.current.date(from: DateComponents(year: 2018, month: 5, day: 28))!, Calendar.current.date(from: DateComponents(year: 2018, month: 10, day: 28))! ] // 在拦截方法里判断 if excludedDates.contains(where: { Calendar.current.isDate(fireDate, inSameDayAs: $0) }) { completionHandler([]) } else { completionHandler([.alert, .sound]) }
方法二:拆分重复通知(备选方案)
如果不想用代理拦截,也可以拆分原有的重复通知:
- 先创建一个从起始日期到排除日期前一个月的重复通知,然后在排除日期前一天触发一个“取消原通知”的操作;
- 取消原通知后,再创建一个从排除日期下一个月开始的重复通知。
不过这种方法需要额外管理多个通知和取消逻辑,复杂度比代理方法高,所以更推荐第一种方法。
内容的提问来源于stack exchange,提问作者Marlon
相关产品推荐
相关产品推荐

