问题
I would like to send a local notification once 24 hours has passed after a button is selected. The button is currently only enabled once 24 hours has passed and the waiting time is saved in UserDegaults. I would like to know how I will be able to send a local notification to the user automatically once the 24 hours has passed.
func getNextQuote(){
let defaults = UserDefaults.standard
defaults.integer(forKey: "savedIndexKey")
let currentIndex = defaults.integer(forKey: "savedIndexKey")
var nextIndex = currentIndex+1
nextIndex = quotes.indices.contains(nextIndex) ? nextIndex : 0
defaults.set(nextIndex, forKey: "savedIndexKey")
let savedInteger = defaults.integer(forKey: "savedIndexKey")
saved = savedInteger
quotesLabel.text = quotes[savedInteger]
self.quotesLabel.fadeIn()
set24HrTimer()
update()
}
func update(){
if let waitingDate = UserDefaults.standard.value(forKey: "waitingDate") as? Date{
if let waitingDate = UserDefaults.standard.object(forKey: "waitingDate") as? Date,
waitingDate < Date() {
self.timeLabel.text = "Please check in for the day"
self.remainingLabel.text = "Did you stay clean today?"
self.remainingLabel.font = UIFont(name: "Arial", size: 32)
self.quotesLabel.isHidden = true
addButton.isHidden = false
noButton.isHidden = false
gridButton.isHidden = false
self.view.setNeedsDisplay()
print("time is up")
}else if let waitingDate = UserDefaults.standard.value(forKey: "waitingDate") as? Date {
self.timeLabel.attributedText = self.timeLeftExtended(date: waitingDate)
addButton.isHidden = true
noButton.isHidden = true
gridButton.isHidden = true
self.quotesLabel.isHidden = false
self.remainingLabel.text = "Until next check in"
self.quotesLabel.fadeIn()
print("still running")
}else{
let newDate = Calendar.current.date(byAdding: .hour, value: 24, to: Date())
UserDefaults.standard.set(newDate, forKey: "waitingDate")
self.timeLabel.attributedText = self.timeLeftExtended(date: newDate!)
print("last option")
}
}
}
func set24HrTimer() {
let currentDate = Date()
let newDate = Date(timeInterval: 86400, since: currentDate as Date)
UserDefaults.standard.setValue(newDate, forKey: "waitingDate")
print("24 hours started")
}
func timeLeftExtended(date:Date) ->NSAttributedString{
let cal = Calendar.current
let now = Date()
let calendarUnits:NSCalendar.Unit = [NSCalendar.Unit.hour, NSCalendar.Unit.minute, NSCalendar.Unit.second]
let components = cal.dateComponents([.hour, .minute, .second], from: now, to: date)
let fullCountDownStr = "\(components.hour!)h \(components.minute!)m \(components.second!)s "
let mutableStr = NSMutableAttributedString(string: fullCountDownStr, attributes: [NSAttributedString.Key.foregroundColor:UIColor.white])
for (index, char) in mutableStr.string.enumerated()
{
if(char == "h" || char == "m" || char == "s")
{
mutableStr.removeAttribute(NSAttributedString.Key.foregroundColor, range: NSMakeRange(index, 1))
mutableStr.addAttributes([NSAttributedString.Key.foregroundColor : UIColor.lightGray], range: NSMakeRange(index, 1))
}
}
return mutableStr
}
func setupTimer()
{
if(!timeWorking)
{
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.updateCountDown), userInfo: nil, repeats: true)
self.timeWorking = true
}
}
回答1:
You shouldn't use a timer to trigger a local notification. This function could be added as an extension to UIViewController
that will let you create a UNCalendarNotificationTrigger
:
import UserNotifications
import UIKit
extension UIViewController {
func createLocalNotification(title: String, hours: Int) {
let seconds = hours * 3600
let content = UNMutableNotificationContent()
content.sound = UNNotificationSound.default
content.title = title
let nextTriggerDate = Calendar.current.date(byAdding: .second, value: seconds, to: Date())!
let comps = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: nextTriggerDate)
let trigger = UNCalendarNotificationTrigger(dateMatching: comps, repeats: false)
let request = UNNotificationRequest(identifier: "\(seconds)", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
}
And can be used within your UIViewController
as follows:
let MyViewController: UIViewController {
@IBAction func buttonPressed(_ sender: Any) {
self.createLocalNotification(title: "24 hours have passed!", hours: 24)
}
}
来源:https://stackoverflow.com/questions/58332313/send-a-local-notification-when-timer-is-up