iOS平台UNUserNotificationCenter条件化重复通知调度及限制问题
iOS重复本地通知实现与批量任务处理指南
嘿,我来帮你理清楚iOS重复本地通知的实现思路,还有100个任务批量处理的方案~
一、三种重复场景的具体实现
iOS的UserNotifications框架里,UNCalendarNotificationTrigger是实现按日期/周/月重复通知的核心,下面分场景给你具体代码和注意事项:
1. 每日推送直至指定日期
创建一个匹配固定时分的日历触发器,设置重复为true,但系统不会自动终止,所以需要我们手动检查截止日期并清理通知。
// 1. 构建通知内容 let content = UNMutableNotificationContent() content.title = "任务提醒" content.body = "记得检查任务完成情况哦" content.sound = UNNotificationSound.default // 2. 设置每日触发的时间(比如早上9点) var dateComponents = DateComponents() dateComponents.hour = 9 dateComponents.minute = 0 // 3. 创建重复触发器 let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true) // 4. 生成唯一标识符(建议关联任务ID,方便后续管理) let taskId = "123" // 替换为你的任务唯一ID let requestIdentifier = "daily_task_\(taskId)" // 5. 创建并添加通知请求 let request = UNNotificationRequest(identifier: requestIdentifier, content: content, trigger: trigger) UNUserNotificationCenter.current().add(request) { error in if let error = error { print("添加每日通知失败: \(error.localizedDescription)") } }
终止逻辑:当APP启动、用户点击通知,或者任务截止日期到达时,遍历待处理通知,移除超过截止日的请求:
UNUserNotificationCenter.current().getPendingNotificationRequests { requests in let expiredIdentifiers = requests.filter { request in // 根据request的identifier解析对应的任务,检查是否过期 let taskId = request.identifier.replacingOccurrences(of: "daily_task_", with: "") guard let task = yourTaskManager.getTask(withId: taskId) else { return true } return Date() > task.endDate }.map { $0.identifier } UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: expiredIdentifiers) }
2. 每周一推送直至指定日期
和每日逻辑类似,只需要在DateComponents里指定weekday(注意iOS中weekday=1是周日,2是周一):
var dateComponents = DateComponents() dateComponents.weekday = 2 // 周一 dateComponents.hour = 9 dateComponents.minute = 0 let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true) let requestIdentifier = "weekly_task_\(taskId)" let request = UNNotificationRequest(identifier: requestIdentifier, content: content, trigger: trigger) UNUserNotificationCenter.current().add(request)
终止逻辑和每日场景一致,只需对应修改标识符的前缀即可。
3. 每月指定日期推送直至指定日期
设置DateComponents的day字段为你需要的日期(比如每月15号),注意如果当月没有该日期(比如2月没有30号),系统会自动调整到当月最后一天触发:
var dateComponents = DateComponents() dateComponents.day = 15 // 每月15号 dateComponents.hour = 9 dateComponents.minute = 0 let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true) let requestIdentifier = "monthly_task_\(taskId)" let request = UNNotificationRequest(identifier: requestIdentifier, content: content, trigger: trigger) UNUserNotificationCenter.current().add(request)
终止逻辑同样参考每日场景,检查任务截止日期后清理无效通知。
二、单个APP的通知数量限制与100个任务的处理方案
关于通知数量限制
iOS官方没有明确限制单个APP的待处理通知请求数量,但实际测试中,100个完全在系统承载范围内,不会有性能问题。如果数量达到几千级,可能会出现系统优化清理的情况,但100个完全不用担心。
100个任务的批量处理技巧
- 统一标识符规范:给每个通知请求设置唯一且可解析的标识符,比如
"{repeatType}_task_{taskId}",这样能快速关联到对应的任务,方便后续查找、修改或删除。 - 避免重复添加:在添加新通知前,先检查是否已有相同标识符的待处理请求,避免重复调度:
UNUserNotificationCenter.current().getPendingNotificationRequests { requests in let existingIds = requests.map { $0.identifier } let targetId = "daily_task_123" if existingIds.contains(targetId) { UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [targetId]) } // 再添加新的通知请求 }
- 批量清理无效通知:APP启动时统一检查所有待处理通知,移除已完成、过期的任务对应的通知,保持通知列表的整洁。
- 任务状态联动:当任务完成、截止日期修改或被删除时,立即移除对应的通知请求,避免无效通知打扰用户。
三、额外注意事项
- 权限检查:确保已经通过
UNUserNotificationCenter.current().requestAuthorization()获取了用户的通知权限(包括alert、sound等),否则通知无法推送。 - 时区适配:
DateComponents默认使用用户当前时区,如果需要固定时区(比如服务器时区),可以设置dateComponents.timeZone = TimeZone(identifier: "Asia/Shanghai")。 - 后台处理:如果APP在后台,通知触发时可以通过
UNUserNotificationCenterDelegate的userNotificationCenter(_:didReceive:withCompletionHandler:)方法处理,此时可以检查任务状态,决定是否继续调度或清理通知。
内容的提问来源于stack exchange,提问作者A.s.ALI
相关产品推荐
相关产品推荐

