Core Data and Notification Identifier SWIFTUI - swift

I'm trying to create a notification using information from a user-created object in CoreData. However, I can't find a good property of the CoreData object to set as an identifier for the notification. I tried using the 'name' property of the object but there might be other objects with the same input so that is not a very safe approach.
How can I set a unique identifier for each notification that I can read from an object in CoreData?
My code is still too messy to post here but I can clear it up if you want.
Below is the latest approach I tried but this seems to be not working. It behaves as if ID is not a unique property.
let content = UNMutableNotificationContent()
content.title = "Reminder"
content.body = name
content.sound = UNNotificationSound.default
let identifier = "\(Reminder.ID.self)"
let calendar = Calendar.current
var reminderDate = DateComponents()
reminderDate = calendar.dateComponents([.year,.month,.day,.hour,.minute], from: remdate)
let trigger = UNCalendarNotificationTrigger(dateMatching: reminderDate, repeats: true)
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request)

Related

How to fix repeated duplicate notifications problem in macOS app

I have created a UNNotificationRequest with following code in a macOS app
let content = UNMutableNotificationContent()
content.title = "Welcome"
content.body = "body"
content.sound = UNNotificationSound.default
var dateComponent = DateComponents()
dateComponent.year = 2021
dateComponent.day = 24
dateComponent.hour = 12
dateComponent.minute = 27
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponent, repeats: true)
let request: UNNotificationRequest = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (error) in
}
I want the notification to trigger on 24th of every month in 2021.
When the notification is triggered, it generates repeated duplicate notifications every second.
If I make the year attribute in datecomponents to nil, then it does not generate repeated duplicate notifications.
But I need to set the year attribute according to my requirement. I tried the same code in a sample iOS app. It does not generate duplicate notifications. It generates only in macOS app.
What is the solution for not generating repeated duplicate notifications if I set the year attribute in datecomponents?

ios - waiting 24hrs to send a notification

Our application sends a notification every morning at 8am to greet the user and remind him to complete a task. Here is the script we are using:
let center = UNUserNotificationCenter.current()
center.removePendingNotificationRequests(withIdentifiers: ["dailyReminder"])
let content = UNMutableNotificationContent()
content.title = "Good morning"
content.body = notificationMessages[randomIndex]
content.sound = .default
var dateComponents = DateComponents()
dateComponents.hour = 8
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let request = UNNotificationRequest(identifier: "dailyReminder", content: content, trigger: trigger)
center.add(request)
This is called after the user finishes the day's task so that they are prompted the next day. However, some people finish the task before 8am. In those cases we'd like for the notification to be sent at 8am of the next day.
How could I calculate if the script runs before or after 8 and add 24 hrs accordingly?
Since this is run locally you could just save the last time the function was sent by holding it in a UserDefault. For example, add the following to the code to save when the user has last done a task:
UserDefaults.standard.set("/(youWillWriteAFunctionForDate)", forKey: "checkTaskOfDate")
Then you can simply check if it was sent today, and plan accordingly:
defaults.string(forKey: "checkTaskOfDate") ?? "Never Done"

How do you send notifications based on user input? SWIFT

How do you set the notification time to match the input of the user?
If a notification reminds the user of new content (i.e the word of the day), is that considered a local notification or a push notification?
The userSelectedTime variable is created when they press done, but I don't know how to pass it on to my sendNotification function which uses DateComponents() to set the time.
#objc func donePressed() {
// formatter
let formatter = DateFormatter()
formatter.dateStyle = .none
formatter.timeStyle = .short
var userSelectedTime = timeTextField.text
userSelectedTime = formatter.string(from: timePicker.date)
print(userSelectedTime)
self.view.endEditing(true)
}
func sendNotification() {
// Default time 10:30, but base it on userSelectedTime if not void
var dateComponents = DateComponents()
dateComponents.hour = 10
dateComponents.minute = 30
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: createNotificationContent(for: myData), trigger: trigger)
center.add(request)
}
First I will answer your question 2. - This mostly depends on where that information is coming from. If the "word of the day" is something you have stored internally inside the app, you can schedule a local notification with that information. However, if you want to change the word of the day externally every day, you will have to create a push notification to achieve this. (At least the only way to make it work properly). Push notifications would require some sort of service to push those to the app so the easiest for you is to go with the local notifications.
To summarize question 2:
Local notification: Something that is created within the app.
Push notification: Information 'pushed' from an external source.
Question 1:
You can do this in a number of ways. What I would recommend from looking at what you already have is to create the date components with the selected time and pass those components to your 'sendNotification()' function.
As an example:
// Capture the time and turn them into components
func donePressed() {
let calendar = Calendar.current
let components = calendar.dateComponents([.hour, .minute, .month, .year, .day], from: timePicker.date)
sendNotification(components: components)
}
// Schedule the notificaiton based on components
func sendNotification(components: DateComponents) {
let trigger = UNCalendarNotificationTrigger(dateMatching: components, repeats: true)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: createNotificationContent(for: myData), trigger: trigger)
center.add(request)
}
Now... I can't see all your code, so I assume that what else you got going is working properly. But I hope you get the concept. I would however recommend creating a separate class like "NotificationScheduler" to handle these things, that way you will be able to separate things a bit more.

Is it possible to mutate the content of a local notification in swift?

In the next version of my app, I want to integrate the possibility that the user can enable weekly reports like the screentime feature from apple.
I know how to setup Local Notifications (The code is already working for other types of notifications like reminders for events), but for this idea, I need the notification text to be updated shortly before firing because I don`t know the exact content of the notification when I add it to the NotificationCenter.
Is there a function which is called shortly before firing or how would I do this?
This is my working code for scheduling notifications:
fileprivate func generateNotification(title: String, body: String, triggerDate: DateComponents) -> String{
//Trigger
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDate, repeats: false)
//Content
let content = UNMutableNotificationContent()
content.title = title
content.body = body
content.sound = UNNotificationSound.default
//Request
let identifier = UUID().uuidString
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.add(request) { (error) in
if let error = error {
print("Error \(error.localizedDescription)")
}
}
return identifier
}

Swift firebase listener object deallocated from memory

I have a chat feature that utilizes a firebase listener that fires when a "new message" is made in order to launch a notification. The problem is that the listener object gets deallocated from memory so there will be no notifications. After researching I have found that I need to use a data service class to hold the listener object to keep it in memory.
Keep a Firebase listener in memory when the app is in background
I am using MySQL to hold the chat IDS and doing an http request to fetch them in ViewDidAppear. Then I am looping through the array of IDs to attach the listeners like so:
for value in informationArray {
let chatRef = DatabaseReference.chats.reference()
let query = chatRef.queryOrdered(byChild: "uid").queryEqual(toValue: (value))
query.observe(.childAdded, with: { snapshot in
let chat = Chat(dictionary: snapshot.value as! [String : Any])
if !self.chats.contains(chat) {
self.chats.insert(chat, at: 0)
self.tableView.reloadData()
//self.fetchChats()
}
chat.ref.child("lastMessage").observe(.value, with: { snapshot in
//(some code that performs tasks specific to this view controller)
let content = UNMutableNotificationContent()
content.title = "You have a new Message!"
content.subtitle = chatTitle
content.body = chat.lastMessage
content.badge = 1
let trigger = UNTimeIntervalNotificationTrigger (timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: "timerDone", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
})
chat.ref.child("lastUpdate").observe(.value, with: { snapshot in
//(some more code that performs tasks specific to this view controller)
I need to keep the reference for "lastMessage" turned on so I will continue to get the notifications. I also need this reference to perform the additional VC tasks. Finally, I have to keep the additional references (chat.ref.child...) though they can be deallocated. How can I setup my data service class to accomplish my goals?