75227


## 現在時刻から少しずらしたローカル通知がうまくいかない

Swiftで現在時刻から`１０秒`時間をずらして通知を表示したい際に`trigger`のDateComponentsの`seconds`をいじってやりたいと思っていますが、通知が表示されません。triggerが`nil`である即時通知はうまくいきます。

## 動かないコード

[code]

    let notificationContent = UNMutableNotificationContent()
    notificationContent.title = "お知らせ"
    notificationContent.body  = "通知内容"
    notificationContent.sound = UNNotificationSound.default
    
    let date = Date()
    var dateComponent = Calendar.current.dateComponents(in: TimeZone.current, from: date)
    dateComponent.second! = 10 // 現在時刻から10秒ずらす
    
    let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponent, repeats: false)
    let request = UNNotificationRequest(identifier: "notification", content: notificationContent, trigger: trigger)
    UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
    
[/code]

## 動くコード(即時通知)

triggerをnilにして即時通知は動作してくれます。

[code]

    let notificationContent = UNMutableNotificationContent()
    notificationContent.title = "お知らせ"
    notificationContent.body  = "通知内容"
    notificationContent.sound = UNNotificationSound.default
    
    let request = UNNotificationRequest(identifier: "notification", content: notificationContent, trigger: nil)
    UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
    
[/code]


CC BY-SA 4.0
2021-04-12T12:47:24.863
75226
2021-04-12T14:32:11.137
40856
question
swift
Swiftで現在時刻から少しずらしたローカル通知がうまくいかない


現在の`dateComponent`を作るコード:

[code]

    let date = Date()
    var dateComponent = Calendar.current.dateComponents(in: TimeZone.current, from: date)
    dateComponent.second! = 10 // 現在時刻から10秒ずらす
    
[/code]

には、2点ほど大きな問題点があります。

  * `dateComponent.second! = 10`は「現在時刻から10秒ずらす」のではなく、「現在時刻の秒だけを10に書き換える」ものです

例えば現在時刻の秒が20の時にこの処理で作られた`dateComponent`は過去の時刻を表すことになり、決してマッチすることはありません。

  * `dateComponents(in:from:)`で作成される`DateComponents`には、「時刻がマッチしたかどうか」の判定に必要以上の情報が含まれる

`print(dateComponent)`としてやると、`calendar: gregorian (current) timeZone:
Asia/Tokyo (current) era: 1 year: 2021 month: 4 day: 12 hour: 23 minute: 9
second: 17 nanosecond: 925995945 weekday: 2 weekdayOrdinal: 2 quarter: 0
weekOfMonth: 3 weekOfYear: 15 yearForWeekOfYear: 2021 isLeapMonth:
false`のような感じになります。一番まずいのは`nanosecond`まで含まれている点だと思われますが、条件が厳しくなりすぎて、やはりマッチすることはまずあり得ない状態になります。

* * *

「現在時刻から10秒後」を表す`DateComponents`が欲しければ、例えばこんな風にします。

[code]

            let date = Date()
            let dateComponent = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date + 10) //<- 現在時刻から10秒後
            print(dateComponent) //-> year: 2021 month: 4 day: 12 hour: 23 minute: 25 second: 14 isLeapMonth: false 
    
[/code]

* * *

実際に「現在時刻から１０秒時間をずらして通知を表示したい」場合には、

[code]

            let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
    
[/code]

のように`UNTimeIntervalNotificationTrigger`を使うべきところでしょうが、今回は`UNCalendarNotificationTrigger`を使う練習ということでしょうか。


CC BY-SA 4.0
2021-04-12T14:32:11.137
75227
2021-04-12T14:32:11.137
13972
75226
answer