Removing scheduled local notification

人盡茶涼 提交于 2021-01-28 22:38:08

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!