问题
I know there are plenty of similar questions and answers, and I reviewed them all, but still cannot find the solution. Despite of removing a scheduled notification from UNUserNotificationCenter
it still gets triggered.
I create local notification as follows:
let aDF = DateFormatter()
aDF.dateFormat = "yyyy-MM-dd HH:mm:ss"
var identifierST = ""
if update == true {
identifierST = myCoreDataEntity.notificationUID!
} else {
identifierST = aDF.string(from: Date())
}
let notif = UNMutableNotificationContent()
notif.title = "some string"
notif.body = "some string"
var dateComp: DateComponents
switch myCoreDataEntity.schedule {
case 1: //daily
dateComp = Calendar.current.dateComponents([.hour, .minute], from: myCoreDataEntity.date)
case 2: //weekly
dateComp = Calendar.current.dateComponents([.weekday, .hour, .minute], from: myCoreDataEntity.date)
case 3: //monthly
dateComp = Calendar.current.dateComponents([.day, .hour, .minute], from: myCoreDataEntity.date)
case 4: //quartely - this is actually not quarterly, dont know how to set quarterly, setting monthly
dateComp = Calendar.current.dateComponents([.day, .hour, .minute], from: myCoreDataEntity.date)
case 5: //halfyearly - this is actually not halfyearly, dont know how to set halfyearly, setting monthly
dateComp = Calendar.current.dateComponents([.day, .hour, .minute], from: myCoreDataEntity.date)
case 6: //yearly
dateComp = Calendar.current.dateComponents([.month, .day, .hour, .minute], from: myCoreDataEntity.date)
default: //monthly
dateComp = Calendar.current.dateComponents([.day, .hour, .minute], from: myCoreDataEntity.date)
}
dateComp.hour = 10
dateComp.minute = 0
let notificationTrigger = UNCalendarNotificationTrigger(dateMatching: dateComp, repeats: true)
let request = UNNotificationRequest.init(identifier: timeStampST, content: notif, trigger: notificationTrigger)
UNUserNotificationCenter.current().add(request) { (error) in
if (error != nil) {
print (error) //notify user that reminder was not saved
} else {
myCoreDataEntity.notificationUID = identifierST
}
}
notificationUID
is a String Attribute on a CoreData Entity where I store created notification identifier, so I could retrieve it later.
The above works correctly, notification is scheduled and delivered on defined date and time, so no problem here.
Whenever I need to remove a particular notification, I retrieve saved notification identifier (notificationUID
) and pass it to the following function:
func removeExisting(identifierST: String) {
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [identifierST])
}
When trying to find the issue, I've retrieved all pending notifications and compared their identifiers
with the identifierST
I am passing to removePendingNotificationRequests
and they match
UNUserNotificationCenter.current().getPendingNotificationRequests(completionHandler: { requests in
for request in requests {
print("==============================================")
print(request.identifier)
print(request.content.title)
print(request.content.subtitle)
print(request.content.body)
}
})
But those cancelled notifications are still being triggered, am I missing something obvious here?
Edit 1
To provide a bit more details on app logic and scenarios:
App creates some events recurring daily, weekly, monthly, etc
For each event a notification is created
Notification is sent on the date of event
The user can see upcoming events and can chose to skip one cycle => this is were the problem is -> when user choses to skip, I run the
func removeExisting(identifierST: String)
to remove it, but when the date of that skipped event comes, the notification is still being sent.
Edit 2
Re: the point on possible typo or logic mistake while removing the notification - the reason I am sure there is no mistake there, is because it works when I am not skipping or editing the event, but I am deleting it, i.e. let's say event date is tomorrow and notification is scheduled to be delivered tomorrow at 10:00. Today user decides that he does not want this even at all and deletes it, so I run func removeExisting(identifierST: String)
and it works -> no notification of that event is generated tomorrow.
But, if the user decides not to delete completely, but just skip 1 day tomorrow, and continue with it the day after tomorrow (in cases when schedule is daily) this is where I get the problem. I've tried to address this scenario in 3 approaches:
Approach 1 - Delete existing notification and create a new one with new identifier and new trigger date - the day after tomorrow
Approach 2 - Create notification with the same identifier (assuming that this will not create a new one but will modify the existing one) but new trigger date - the day after tomorrow
Approach 3 - Delete existing notification and create a new one with the same identifier and new trigger date - the day after tomorrow
None of this works.
回答1:
First, let me explain why what you're doing is not working.
Let's say you have many different dates, for example: April 27th, May 4th, May 11th, May 18th etc..
You're assigning dateComp as
dateComp = Calendar.current.dateComponents([.weekday, .hour, .minute], from: myCoreDataEntity.date)
so for each of those mentioned dates your dateComp will look like:
dateComp = [Monday, 10, 30] // April 27th
dateComp = [Monday, 10, 30] // May 4th
dateComp = [Monday, 10, 30] // May 11th
dateComp = [Monday, 10, 30] // May 18th
and next you put that dateComp in your trigger, do you see where i'm going with this? Trigger doesn't have anything to do with your date except those three parameters, by changing date week later, you're actually using exactly the same trigger.
The moment you add your request to notification center your notification is set up to show on NEXT AVAILABLE Monday at 10:30, NOT on your date Monday 10:30.
I had the same problem and posted similar question here. From all my research and what others said it is not possible to set up repeated notification from specific future date in current UNNotificationCenter, i will be more than happy if someone could prove me wrong about this.
You could set up whole dateComp from your date, for example [.month, .day, .hour, .minute] but then if you set repeat to true it will repeat only on the same [.month, .day, .hour, .minute] which will end up repeating yearly.
Solution can be either to set up non-repeating notification for each specific date (there is limit of 64 notifications you can have in the same time) or like in my case set up seven repeating notifications for each weekday and then just remove the one you don't want at a time and add it again some other day but NOT the same day yet because it will be triggered again.
You can check out code i used in my app to do that here:
How to set up daily local notification for tasks but don't show it when user completes the task before
回答2:
You mean, you call getPendingNotificationRequests and no longer see the one you removed? Then, are you sure the code to add is not being called by accident after that? (so it could be being added again?)
One feature of UNUserNotificationCenter.current().add()
is that, if a notification with the desired ID is already scheduled, it will not schedule another notification at the same time, but it will also not give an error. You can think of it as that it over-writes the existing one. So, if your code is somehow scheduling the same notifications again and again, you would probably not notice. Until you try removing notifications, and then they get rescheduled.
回答3:
I've now watched again related WWDC video - https://developer.apple.com/videos/play/wwdc2016/707 - and changed the logic a bit.
Original approach
When user is skipping a cycle, I am removing scheduled notification and creating a new one, with new identifier and new trigger date.
New approach
When user is skipping a cycle, I am not removing anything, but creating a "new" notification with a new trigger date, but using the same identifier. As I understand from the video, using the same identifier is not actually creating a new notification, but updating the exisintg one. I will be able to confirm if this works in 24 hours.
来源:https://stackoverflow.com/questions/61360998/removing-scheduled-local-notification