Does UNTimeIntervalNotificationTrigger nextTriggerDate() give the wrong date?
Asked Answered
M

1

10

I’m updating my localnotifications to work with iOS 10 and I’ve run into an issue where I think the nextTrigger function returns NOT “The next date at which the trigger conditions will be met.” but instead returns whatever the current date time is PLUS what you had initially set the UNTimeInvervalNotificationTrigger to.

So if you set the trigger to go off in 60 seconds, from the documentation I expect that when I call the nextTriggerDate() that I’d get it to return whatever the date time is when I set the trigger + 60 seconds. So if I set it at 12:00:00, I’d expect that the nextTriggerDate() would be 12:01:00. However what I’m experiencing is that it returns whatever the current date is + 60 seconds.

I wrote a sample that schedules a UNTimeIntervalNotificationTrigger and then prints out the nextTriggerDate() every second. When I run this I get a new nextTriggerDate every second. Like this:

            //Optional(2016-11-03 21:26:31 +0000)
            //Optional(2016-11-03 21:26:32 +0000)
            //Optional(2016-11-03 21:26:33 +0000)
            //Optional(2016-11-03 21:26:34 +0000)
            //Optional(2016-11-03 21:26:35 +0000)
            //Optional(2016-11-03 21:26:36 +0000)

I’ve opened a TSI with apple but… you know… that takes awhile. So I thought I’d see if anyone here had any insight. I suspect it’s a bug and if I get more information I’ll update this.

This is the code I’ve used to illustrate the issue:

import UIKit
import UserNotifications

class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
    @IBOutlet weak var setButton: UIButton!

    @IBOutlet weak var timePicker: UIPickerView!

    weak var timer: Timer?

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func setButtonAction(_ sender: UIButton) {
        var mySecond = pickerSelection

        // build notification
        let content = UNMutableNotificationContent()
        content.title = "Title of notification"
        content.body = "This is the body of the notification"
        content.sound = UNNotificationSound.default()
        content.categoryIdentifier = "myCategory"

        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: Double(mySecond), repeats: false)

        let request = UNNotificationRequest(identifier: "test notification", content: content, trigger: trigger)

        UNUserNotificationCenter.current().add(request) {(error) in
            if let error = error {
                print("Uh oh! We had an error: \(error)")
            }
        }

        self.timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.tick), userInfo: nil, repeats: true)
    }

    let pickerData = [":00",":01",":02",":03",":04",":05",":06",":07",":08",":09",":10",":11",":12",":13",":14",":15",":16",":17",":18",":19",":20",":21",":22",":23",":24",":25",":26",":27",":28",":29",":30",":31",":32",":33",":34",":35",":36",":37",":38",":39",":40",":41",":42",":43",":44",":45",":46",":47",":48",":49",":50",":51",":52",":53",":54",":55",":56",":57",":58",":59"]


    var pickerSelection = 0


    override func viewDidLoad() {
        super.viewDidLoad()
        self.timePicker.dataSource = self
        self.timePicker.delegate = self
        self.timePicker.selectRow(pickerSelection, inComponent: 0, animated: false)
    }

    // The number of columns of data
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    // The number of rows of data
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return pickerData.count
    }

    // The data to return for the row and component (column) that's being passed in
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return pickerData[row]
    }

    func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
        let pickerLabel = UILabel()
        let titleData = pickerData[row]
        let myTitle = NSAttributedString(string: titleData, attributes: [NSFontAttributeName:UIFont(name: "Futura", size: 44.0)!])
        pickerLabel.attributedText = myTitle
        pickerLabel.textAlignment = .center

        return pickerLabel
    }

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        pickerSelection = row
    }

    func tick() {
        let center = UNUserNotificationCenter.current()
        center.getPendingNotificationRequests(completionHandler: { (scheduledLocalNotifications) in
            for localNotice in scheduledLocalNotifications {
                var localTrigger = localNotice.trigger as! UNTimeIntervalNotificationTrigger

                var localTime = localTrigger.nextTriggerDate()
                // ** This output shows something like this:

                //Optional(2016-11-03 21:26:31 +0000)
                //Optional(2016-11-03 21:26:32 +0000)
                //Optional(2016-11-03 21:26:33 +0000)
                //Optional(2016-11-03 21:26:34 +0000)
                //Optional(2016-11-03 21:26:35 +0000)
                //Optional(2016-11-03 21:26:36 +0000)
                print("\(localTime)")     
            }
        })
    }
}
Malleolus answered 3/11, 2016 at 21:48 Comment(1)
I met the same problem like you. In my point of view, if i set a timeinterval of 60 minutes at 12 o'clock, the trigger's nextdate is 13 o'clock. However, when i get the request.trigger from UNNotificationCenter, i print the trigger.nextTriggerDate. The date is not 13 o'clock. What' more, the value changes if i print it at different time. Anyway, thanks for your anwser, it works.Standin
M
9

Heard back from Apple DTS and was told that the functionality I'd described was how it was designed to work. Although I had thought the documentation explained it differently they told me that "the documentation was optimistic given the implementation." Anyway, I worked around it by keeping track of the fire date in my code. I hope this answer can help someone else who had the same problem I did.

Malleolus answered 9/11, 2016 at 20:12 Comment(5)
At the time it didn't work the way that I thought it was supposed to work.Malleolus
Are they lying that it's as designed? Next trigger date is not correct so who are they fooling??Archiepiscopal
I need to know, as you too, when trigger will fired and I can't find out how to do that :( Do you find out solution?Standpipe
It still doesn't work at this time. The date it returns seems based on the time when you call the function.Christos
Yeah, you would have to compute this yourself. You could pass something into the userInfo dict to compute this. This is about the dumbest api I've seen to date. How could returning the current date plus the interval be of any help?Screenplay

© 2022 - 2024 — McMap. All rights reserved.