从CoreData存储的Date创建DateComponents触发通知失败求助
解决UNCalendarNotificationTrigger无法按时触发的问题
看起来你的问题核心出在DateComponents的可选属性上——UNCalendarNotificationTrigger要求用于匹配的DateComponents中的组件必须是非可选值,否则会被视为“不限制该组件”,导致触发器无法精准匹配你想要的时间。
问题分析
你从calendar.dateComponents获取的anchorComponents,它的所有属性(比如day、hour等)都是可选类型(因为Calendar无法保证所有组件都能从Date中提取到有效值,虽然你的场景里Date来自UIDatePicker,理论上是完整的)。当你把这些可选属性直接赋值给dateInfo1后,dateInfo1的属性依然是可选的,比如你打印的dateInfo1.hour是Optional(2)。
对于UNCalendarNotificationTrigger来说,只要某个组件是可选的,它就会忽略这个组件的限制——比如hour是可选的,触发器就会匹配任意小时的时间,自然无法在你指定的2点触发通知。
解决方案
你需要把anchorComponents中的可选属性解包,确保dateInfo1的所有必要组件都是非可选值。这里有两种稳妥的方式:
方式1:使用guard let解包必要组件(推荐,更安全)
var date = Date() if let editnote = editnotes { date = editnote.sSelectedDate } else { print("nil") } let calendar = Calendar.current let unitFlags: Set<Calendar.Component> = [.day, .month, .year, .hour, .minute] guard let anchorComponents = calendar.dateComponents(unitFlags, from: date), let day = anchorComponents.day, let month = anchorComponents.month, let year = anchorComponents.year, let hour = anchorComponents.hour, let minute = anchorComponents.minute else { print("无法提取完整的日期组件") return } var dateInfo1 = DateComponents() dateInfo1.day = day dateInfo1.month = month dateInfo1.year = year dateInfo1.hour = hour dateInfo1.minute = minute let trigger = UNCalendarNotificationTrigger(dateMatching: dateInfo1, repeats: false)
方式2:直接强制解包(仅限你确认Date一定包含所有组件的场景)
因为你的Date来自UIDatePicker,它的日期是完整的,所以可以安全地强制解包:
var date = Date() if let editnote = editnotes { date = editnote.sSelectedDate } else { print("nil") } let calendar = Calendar.current let unitFlags: Set<Calendar.Component> = [.day, .month, .year, .hour, .minute] let anchorComponents = calendar.dateComponents(unitFlags, from: date) // 强制解包,因为UIDatePicker的Date必然包含这些组件 var dateInfo1 = DateComponents() dateInfo1.day = anchorComponents.day! dateInfo1.month = anchorComponents.month! dateInfo1.year = anchorComponents.year! dateInfo1.hour = anchorComponents.hour! dateInfo1.minute = anchorComponents.minute! let trigger = UNCalendarNotificationTrigger(dateMatching: dateInfo1, repeats: false)
额外提示
- 你之前尝试直接用
anchorComponents的问题,其实也是因为它的属性是可选的,所以同样会导致触发器失效,并不是复制到新实例的问题,而是可选值的问题。 - 可以在创建触发器前打印
dateInfo1,确认所有组件都是非可选的,比如:print(dateInfo1),正常输出应该是类似year: 2024 month: 10 day: 20 hour: 2 minute: 30 isLeapMonth: false,没有Optional()字样。
内容的提问来源于stack exchange,提问作者Osama Naeem
相关产品推荐
相关产品推荐

