Как я могу получить массив UNNotificationRequest, используя цикл for для заполнения представления списка SwiftUI?

Я хочу просто получить список запланированных локальных уведомлений и заполнить список SwiftUI, используя forEach. Я считаю, что это должно работать так, как я сделал ниже, но массив всегда пуст, поскольку кажется, что он используется до завершения цикла for. Я попробовал функцию getNotifications() с обработчиком завершения, а также в качестве функции возврата, но оба способа все равно не работали. Как я могу дождаться завершения цикла for для заполнения моего списка? Или, если есть другой способ сделать это, пожалуйста, дайте мне знать, спасибо.

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()
    }
}
}

Обновлять:

Вот как я добавляю новое уведомление и снова вызываю getNotifications. Я хочу, чтобы список динамически обновлялся по мере создания нового массива. Печать в консоль показывает, что getNotifications работает правильно, а новый массив содержит добавленное уведомление.

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)

person Peter Ruppert    schedule 25.10.2020    source источник
comment
Я пробовал это, а также использовал group.enter .leave и т. д., и это не сработало.   -  person Peter Ruppert    schedule 26.10.2020


Ответы (1)


Ваш глобальный notificationArray не наблюдается в представлении. Это должно быть динамическое свойство... возможное решение - обернуть его в модель представления ObservableObject.

Вот демонстрация решения:

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()
    }
 }
}
person Asperi    schedule 26.10.2020
comment
Это работает лучше и показывает список, когда я открываю приложение, но, к сожалению, когда я добавляю новое уведомление и снова вызываю self.vm.getNotifications(), он не обновляет мой список, чтобы отразить это. Я что-то упускаю? Я добавил @StateObject var vm = ViewModel() к каждому View, которому это нужно. Добавление того, как я добавляю уведомление к вопросу. - person Peter Ruppert; 26.10.2020
comment
Нет, если это одна и та же модель представления, то ее следует создать один раз, в каком-то корневом представлении, и внедрить для подпредставлений иерархии в качестве объекта среды. Тогда все будут использовать один и тот же экземпляр, а обновление в одном месте приведет к обновлению всех зависимых представлений. - person Asperi; 26.10.2020
comment
Я изменил stateObject на объект среды следующим образом: @EnvironmentObject var vm: ViewModel но теперь получаю сообщение об ошибке, когда список заполняется Thread 1: Fatal error: No ObservableObject of type ViewModel found. A View.environmentObject(_:) for ViewModel may be missing as an ancestor of this view. atm, как работает иерархия, мой основной ContentView содержит ListView, но показывает его только в том случае, если getNotifications возвращает непустое notificationsArray, тогда я хочу, чтобы ListView используйте массив и заполните список. и после этого я хочу, чтобы я мог обновить массив и список shld - person Peter Ruppert; 26.10.2020
comment
Хорошо, теперь я понял и заработал. в моих подпредставлениях я добавил переменную environmentObject: @EnvironmentObject var vm: ViewModel а затем в моем основном представлении, когда я вызываю подпредставление, я сделал так: ListView().environmentObject(vm) Теперь я могу вызвать vm.getNotifications() и список обновлений соответственно. - person Peter Ruppert; 26.10.2020