iosswiftuiunnotificationrequest

How can I get UNNotificationRequest array using for loop to populate SwiftUI List view?


I want to simply get the list of local notifications that are scheduled and populate a SwiftUI List using forEach. I believe it should work like I have done below, but the array is always empty as it seems to be used before the for loop is finished. I tried the getNotifications() function with a completion handler, and also as a return function, but both ways still didn't work. How can I wait until the for loop is done to populate my list? Or if there is another way to do this please let me know, thank you.

var notificationArray = [UNNotificationRequest]()

func getNotifications() {
        
print("getNotifications")
        center.getPendingNotificationRequests(completionHandler: { requests in
            for request in requests {
                print(request.content.title)
                notificationArray.append(request)
            }
        })

}

struct ListView: View {

var body: some View {
    
    NavigationView {
    List {
        ForEach(notificationArray, id: \.content) { notification in

            HStack {
                VStack(alignment: .leading, spacing: 10) {
                    let notif = notification.content
                    Text(notif.title)
                    Text(notif.subtitle)
                    .opacity(0.5)
            }
                    }
        
    }

}
 .onAppear() {
        getNotifications()
    }
}
}

Update:

Here is how I am adding a new notification and calling getNotifications again. I want the list to dynamically update as the new array is made. Printing to console shows that the getNotifications is working correctly and the new array contains the added notiication.

Section {
                Button(action: {
                    print("Adding Notification: ", title, bodyText, timeIntValue[previewIndex])
                    addNotification(title: title, bodyText: bodyText, timeInt: timeIntValue[previewIndex])
                    showDetail = false
                    self.vm.getNotifications()
                }) {
                    Text("Save Notification")
                }
            }.disabled(title.isEmpty || bodyText.isEmpty)

Solution

  • Your global notificationArray is not observed by view. It should be dynamic property... possible solution is to wrap it into ObservableObject view model.

    Here is a demo of solution:

    class ViewModel: ObservableObject {
      @Published var notificationArray = [UNNotificationRequest]()
    
      func getNotifications() {
            
        print("getNotifications")
            center.getPendingNotificationRequests(completionHandler: { requests in
                var newArray = [UNNotificationRequest]()
                for request in requests {
                    print(request.content.title)
                    newArray.append(request)
                }
                DispatchQueue.main.async {
                  self.notificationArray = newArray
                }
            })
      }
    }
    
    struct ListView: View {
      @ObservedObject var vm = ViewModel()
    //@StateObject var vm = ViewModel()    // << for SwiftUI 2.0
    
      var body: some View {
        
        NavigationView {
          List {
            ForEach(vm.notificationArray, id: \.content) { notification in
                HStack {
                    VStack(alignment: .leading, spacing: 10) {
                        let notif = notification.content
                        Text(notif.title)
                        Text(notif.subtitle)
                        .opacity(0.5)
                    }
                }
          }
       }
       .onAppear() {
            self.vm.getNotifications()
        }
     }
    }