Search code examples
swiftcore-dataswiftuiuilocalnotificationlocalnotification

Delete Local Notification if removed from Core Data SwiftUI


I made this simple code to try how Local Notifications works with Core Data and the main problem is that, after adding a Data Core item, I can receive my notification after 60 seconds but if I remove it I still receive it. Is there a function that I can call to delete that specific notification when I call my deleteItem function?

Another question that I have is how can I set a day of the week and timing to trigger that notification and not repeating after few seconds?

ContentView:

import UserNotifications
import SwiftUI
import CoreData

struct ContentView: View {
    //Core Data
    @Environment(\.managedObjectContext) var managedObjectContext
    @FetchRequest(entity: Notifications.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Notifications.date, ascending: false)]) var notifications: FetchedResults<Notifications>
    
    var titles = ["Hello", "Weekend", "Streaming", "ScoobyDoo"]
    var subtitles = ["Hello2", "Weekend2", "Streaming2", "ScoobyDoo2"]
    
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: FavoriteView()) {
                    Text("Favorite View")
                }
                List {
                    ForEach(0 ..< titles.count) {title in
                        HStack {
                            Text(self.titles[title])
                            Image(systemName: "heart")
                                .onTapGesture {
                                    if self.checkItem(title: self.titles[title]) {
                                        do {
                                            try self.deleteItem(title: self.titles[title])
                                            print("title deleted")
                                        } catch {
                                            print(error)
                                        }
                                    } else {
                                        self.addItem(item: self.titles[title])
                                        print("item added")
                                        
                                        // Notification content
                                        let content = UNMutableNotificationContent()
                                        content.title = self.titles[title]
                                        content.subtitle = self.subtitles[title]
                                        content.sound = UNNotificationSound.default
                                        
                                        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 60, repeats: true)
                                        
                                        let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
                                        
                                        UNUserNotificationCenter.current().add(request)
                                    }
                            }
                        }
                    }
                }
                
                Button("Request Authorization") {
                    // Ask for notification when app launches
                    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
                        if success {
                            print("All set")
                        } else if let error = error {
                            print(error.localizedDescription)
                        }
                        
                    }
                }
                
                Button("Remove Notifications") {
                    UNUserNotificationCenter.current().removeAllDeliveredNotifications()
                    print("Removed")
                }
            }
        }
    }
    private func checkItem(title: String) -> Bool {
        let request: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Notifications")
        request.predicate = NSPredicate(format: "title == %@", title)
        request.fetchLimit = 1
        var trueFalse = true
        do {
            let count = try managedObjectContext.count(for: request)
            if count == 0 {
                trueFalse = false
            } else {
                trueFalse = true
            }
        } catch {
            print(error)
        }
        return trueFalse
    }
    
    private func deleteItem(title: String) throws {
        let request: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Notifications")
        request.predicate = NSPredicate(format: "title == %@", title)
        try managedObjectContext.execute(NSBatchDeleteRequest(fetchRequest: request))
        
        saveFavorites()
    }
    func addItem(item: String) {
        let newItem = Notifications(context: managedObjectContext)
        newItem.title = item
        saveFavorites()
    }
    func saveFavorites() {
        do {
            try managedObjectContext.save()
        } catch {
            print(error)
        }
    }
}

FavoriteView:

import SwiftUI
import CoreData

struct FavoriteView: View {
    //Core Data
    @Environment(\.managedObjectContext) var managedObjectContext
    @FetchRequest(entity: Notifications.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Notifications.date, ascending: false)]) var notifications: FetchedResults<Notifications>
    
    var body: some View {
        List {
            ForEach(notifications, id: \.self) { item in
                Text(item.title)
            }
        }
    }
}

Solution

  • Modify the core data model to include the notification identifier that you're providing while adding the request. And then while removing the notification from core data you can use this identifier to remove the local notification like this:

    UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [identifier])
    UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [identifier])