Swift单条目本地通知增删实现及标识符匹配问题
问题核心原因
你当前无法正常取消通知的本质问题是:创建通知请求时临时生成的UUID().uuidString作为通知标识符,生成后既没有和你的待办条目做绑定存储,也没有对外返回,后续根本无法获取到这个和系统存储的通知匹配的字符串,自然无法精准定位要取消的通知。
你混淆的三个概念明确如下:
item.id:是你自己业务层定义的待办条目的唯一主键,全程和单条待办绑定、由你可控- 你代码里临时生成的
UUID().uuidString:本质是你传给通知系统的identifier参数值,但因为生成后没有持久化存储、也没有和对应待办关联,创建完就丢失了 identifier:是iOS通知系统识别单条通知的唯一标记,创建通知时你传什么值,系统就存什么值,取消时必须传入和创建时完全一致的字符串,才能匹配到对应通知执行删除操作。
核心逻辑就是保证「创建通知时用的identifier」和「取消时传入的id」完全一致,且和你的待办条目强绑定
修复步骤
- 不要在创建通知时临时生成随机UUID当标识符,直接用待办条目自身的
item.id作为通知的identifier,从根源上保证待办条目和对应通知一一绑定,不需要额外存储映射关系。 - 修复原代码里日期组件漏写
year的隐患:原代码只取了月、日、时分秒,跨年设置提醒时会出现触发时间匹配错误的问题。
修改后的可直接用的代码如下:
/// 创建本地通知 /// - Parameters: /// - itemId: 对应待办条目的唯一id,直接传item.id即可 /// - fireDate: 通知触发时间 /// - text: 通知副标题内容 func pushNotification(itemId: String, fireDate: Date, text: String){ let calendar = Calendar.current // 直接一次性取出需要的日期组件,包含year避免跨年bug let dateComponents = calendar.dateComponents( [.year, .month, .day, .hour, .minute, .second], from: fireDate ) let content = UNMutableNotificationContent() content.title = "Organized" content.subtitle = text content.sound = .default content.badge = 1 let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false) // 核心:用待办id作为通知唯一标识,和业务条目强绑定 let request = UNNotificationRequest( identifier: itemId, content: content, trigger: trigger ) UNUserNotificationCenter.current().add(request) } func cancelNotification(ids: [String]) { UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: ids) UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: ids) }
调用方式
- 创建通知时:拿到对应待办条目对象,调用
pushNotification(itemId: item.id, fireDate: 你选择的提醒日期, text: item.title)即可 - 提前完成待办需要取消通知时:直接把当前待办的
item.id放到数组里,调用cancelNotification(ids: [item.id])就能精准删除这条待办对应的未触发通知,不会出现完成后通知还弹的问题。
额外场景适配
如果单条待办支持设置多个提醒(比如提前1天、提前1小时各弹一次),可以通过给id加固定后缀的方式区分多个通知:
- 提前1天的通知identifier设为
"\(item.id)_advance1day" - 提前1小时的通知identifier设为
"\(item.id)_advance1hour"
取消时把该条目对应的所有通知id组装成数组传入即可。
内容的提问来源于stack exchange,提问作者Dorian Hell
相关产品推荐
相关产品推荐

