Schedule local notification every [day, week, month, year, etc] error

33 Views Asked by At

I was creating reminders in my app, Notifications are working, but scheduling them every dateComponent is problematic in my case.

After fixing this problem, it will be nice if someone can tell me how can I do a 'custom' method by picking specific week components for example [monday, tuesday, friday]

Here is my code for adding a request (schedule) local notification

let addRequest = {
            let content = UNMutableNotificationContent()
            
            if !reminder.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
                content.title = reminder.title
            } else {
                content.title = "New Reminder"
            }
            
            content.subtitle = reminder.stringDate
            
            content.sound = UNNotificationSound.defaultRingtone
            
            let calendar = Calendar.current
            
            var alertOptionTime = 0.0
            
            switch alertOption {
            case .noAlerts:
                fatalError("You messed up")
            case .atTimeOfEvent:
                alertOptionTime = 0
            case .fiveMinutes:
                alertOptionTime = -300
            case .tenMinutes:
                alertOptionTime = -600
            case .fifteenMinutes:
                alertOptionTime = -900
            case .thirtyMinutes:
                alertOptionTime = -1800
            case .oneHour:
                alertOptionTime = -3200
            case .twoHours:
                alertOptionTime = -6400
            case .oneDay:
                alertOptionTime = -86400
            case .twoDay:
                alertOptionTime = -172800
            case .oneWeek:
                alertOptionTime = -604800
            }

// This part is somehow wrong ⬇️
            
            var dateComponents: Set<Calendar.Component> = []
            
            switch reminder.repeating {
            case .never:
                dateComponents = [.day, .hour, .minute]
            case .everyDay:
                dateComponents = [.day, .hour, .minute]
            case .everyWeek:
                dateComponents = [.weekday, .day, .hour, .minute]
            case .everyMounth:
                dateComponents = [.month, .weekday, .day, .hour, .minute]
            case .everyYear:
                dateComponents = [.year, .month, .weekday, .day, .hour, .minute]
            case .custom:
                dateComponents = [.day, .hour, .minute] // MARK: Change this in future
            }

// This part is somehow wrong ⬆️
            
            let components = calendar.dateComponents(dateComponents, from: reminder.date.addingTimeInterval(alertOptionTime))
            
            let trigger = UNCalendarNotificationTrigger(dateMatching: components, repeats: reminder.repeating != .never)
            
            let request = UNNotificationRequest(identifier: reminder.id.uuidString, content: content, trigger: trigger)
            
            self.center.add(request)
}
1

There are 1 best solutions below

1
Rob Napier On

I think you've misunderstood how the matching works. The UNCalendarNotificationTrigger docs include an example of the "every day" repeat:

var date = DateComponents()
date.hour = 8
date.minute = 30 
let trigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: true)

This matches the hour and minute. Every time that hour and that minute occur, it will fire, which will be every day (except in some DST adjustment situations).

You've passed:

        case .everyDay:
            dateComponents = [.day, .hour, .minute]

This says the hour, minute, and day-of-month must all match. So this is monthly.

        case .everyWeek:
            dateComponents = [.weekday, .day, .hour, .minute]

This one says "every time the day-of-week and day-of-month and hour and minute match." So this would be every time the given day of the month falls on the given day of the week (i.e. a couple of times a year).

I believe you meant something like:

        case .never:
            dateComponents = [.hour, .minute]
        case .everyDay:
            dateComponents = [.hour, .minute]
        case .everyWeek:
            dateComponents = [.weekday, .hour, .minute]
        case .everyMounth:
            dateComponents = [.day, .hour, .minute]
        case .everyYear:
            dateComponents = [.month, .day, .hour, .minute]
        case .custom:
            ...
        }

To your question about multiple times in a week, you would need to set up multiple notifications, one for each day of the week you want.