#ios #swift #uilocalnotification #nsdatecomponents #unusernotificationcenter
Вопрос:
Я полагаю, что об этом спрашивали несколько раз, но четкого ответа нет.
Существует два способа запланировать временные уведомления: UNCalendarNotification
и UNTimeIntervalNotificationTrigger
.
Планирование уведомления на определенное время и день недели тривиально, как и в определенный день месяца, но планирование на определенное время каждые n дней не так тривиально.
Например, каждые 5 дней в 11:00.
UNTimeIntervalNotificationTrigger
может показаться, что это подходящий класс для поиска, за исключением проблем, возникающих при переходе на летнее время или изменении часового пояса. Например, летнее время заканчивается, и теперь ваше уведомление в 10:00 вместо 11:00.
day
Свойство DateComponents
класса вместе с UNCalendarNotification
классом может содержать решение, потому что в документах указано «День или количество дней«. Я интерпретирую это как «Определенный день месяца (день) или n дней (количество дней)».
Углубившись в day
документы свойств, он читает: «Это значение интерпретируется в контексте календаря, в котором оно используется».
Как вы можете использовать day
свойство вместе с контекстом календаря для работы с количеством дней вместо конкретных дней месяца?
Кроме того, документы для свойств hour
и minute
в DateComponents
также читают «Час или количество часов» и «Минута или количество минут» соответственно. Итак, даже если бы вы установили day
значение «количество дней», как бы вы могли установить hour
и minute
правильно?
Очевидно, что эта функциональность возможна в iOS — приложение «Напоминания» является доказательством этого.
Комментарии:
1. Каждые n дней, исходя из какой даты? И нет никакой разницы, пока вы придерживаетесь одного и того же часового пояса или просто не устанавливаете разницу во времени вообще.
2. @ElTomato Спасибо за ваш комментарий, да, «каждые n дней» нужна дата привязки, но как вы устанавливаете дату привязки? Я понимаю
calendar
, что свойство может быть включеноDateComponents
, но меняет ли это контекст при установкеday
свойства с «день» на «количество дней»?3. Видеть
date(byAdding:to:options:)
. Вы можете использовать.day
.
Ответ №1:
Вы можете настроить их заранее, используя UNCalendarNotificationTrigger
n
несколько раз и используя скорректированный календарь для текущего часового пояса
import SwiftUI
class NotificationManager: NSObject, UNUserNotificationCenterDelegate{
static let shared: NotificationManager = NotificationManager()
let notificationCenter = UNUserNotificationCenter.current()
private override init(){
super.init()
requestNotification()
notificationCenter.delegate = self
getnotifications()
}
func requestNotification() {
print(#function)
notificationCenter.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
if let error = error {
// Handle the error here.
print(error)
}
// Enable or disable features based on the authorization.
}
}
/// Uses [.day, .hour, .minute, .second] in current timeZone
func scheduleCalendarNotification(title: String, body: String, date: Date, repeats: Bool = false, identifier: String) {
print(#function)
let content = UNMutableNotificationContent()
content.title = title
content.body = body
let calendar = NSCalendar.current
let components = calendar.dateComponents([.day, .hour, .minute, .second], from: date)
let trigger = UNCalendarNotificationTrigger(dateMatching: components, repeats: repeats)
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
notificationCenter.add(request) { (error) in
if error != nil {
print(error!)
}
}
}
///Sets up multiple calendar notification based on a date
func recurringNotification(title: String, body: String, date: Date, identifier: String, everyXDays: Int, count: Int){
print(#function)
for n in 0..<count{
print(n)
let newDate = date.addingTimeInterval(TimeInterval(60*60*24*everyXDays*n))
//Idenfier must be unique so I added the n
scheduleCalendarNotification(title: title, body: body, date: newDate, identifier: identifier n.description)
print(newDate)
}
}
///Prints to console schduled notifications
func getnotifications(){
notificationCenter.getPendingNotificationRequests { request in
for req in request{
if req.trigger is UNCalendarNotificationTrigger{
print((req.trigger as! UNCalendarNotificationTrigger).nextTriggerDate()?.description ?? "invalid next trigger date")
}
}
}
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(.banner)
}
}
class ZuluNotTriggerViewModel:NSObject, ObservableObject, UNUserNotificationCenterDelegate{
@Published var currentTime: Date = Date()
let notificationMgr = NotificationManager.shared
///Sets up multiple calendar notification based on a date
func recurringNotification(title: String, body: String, date: Date, identifier: String, everyXDays: Int, count: Int){
print(#function)
notificationMgr.recurringNotification(title: title, body: body, date: date, identifier: identifier, everyXDays: everyXDays, count: count)
//just for show now so you can see the current date in ui
self.currentTime = Date()
}
///Prints to console schduled notifications
func getnotifications(){
notificationMgr.getnotifications()
}
}
struct ZuluNotTriggerView: View {
@StateObject var vm: ZuluNotTriggerViewModel = ZuluNotTriggerViewModel()
var body: some View {
VStack{
Button(vm.currentTime.description, action: {
vm.currentTime = Date()
})
Button("schedule-notification", action: {
let twoMinOffset = 120
//first one will be in 120 seconds
//gives time to change settings in simulator
//initial day, hour, minute, second
let initialDate = Date().addingTimeInterval(TimeInterval(twoMinOffset))
//relevant components will be day, hour minutes, seconds
vm.recurringNotification(title: "test", body: "repeat body", date: initialDate, identifier: "test", everyXDays: 2, count: 10)
})
Button("see notification", action: {
vm.getnotifications()
})
}
}
}
struct ZuluNotTriggerView_Previews: PreviewProvider {
static var previews: some View {
ZuluNotTriggerView()
}
}
Комментарии:
1. Привет, Лорем ипсум, спасибо за такой подробный ответ. Первоначальная награда за ответ истекла до того, как у меня появилась возможность вознаградить вас, я начал новую и намерен вознаградить ее, как только кнопка станет доступной.