Почему моя логика будущего Combine работает внутри кнопки, но не внутри ее собственной функции, вызываемой кнопкой?

Future не будет работать в кнопке так же, как в своей собственной функции

У меня есть кнопка, которая обновляет мои предстоящие уведомления с помощью Combine, и она работает достаточно хорошо, но по какой-то причине, когда я как можно точнее копирую блок внутри кнопки в его собственную независимую функцию и использую эту функцию в кнопке, это не работает.

Это работает

    Button("updatePendingView") {
        let future = futureUpcomingNotificationRequests()
    
        future
          .map() {
              notificationRequestsToDates(notificationRequests: $0)
          }
          .sink(receiveCompletion: {
                    print("Completed with,", $0)
                },
                receiveValue: {
                    print("Recieved \($0) as an array of Dates")
                    upcomingNotificationDates = $0
                })
          .store(in: &subscriptions)
    
    }

Это не работает (не используется окончательное закрытие для установки массива, который обновляет View)

    @State var upcomingNotificationDates: [Date] = []
    @State var subscriptions = Set<AnyCancellable>()
    
    ...
    
    Button("updatePending with future function") {
        updateNotificationView(subscriptions: subscriptions) {
            upcomingNotificationDates = $0
        }
    }

    func updateNotificationView(subscriptions: Set<AnyCancellable>, closure: @escaping ([Date]) -> ()) {
        var subscriptions = subscriptions
        let future = futureUpcomingNotificationRequests()
    
        future
            .map() {
                notificationRequestsToDates(notificationRequests: $0)
            }
            .sink(receiveCompletion: {
                print("Completed with,", $0)
            },
            receiveValue: {
                print("Recieved \($0) as an array of Dates")
                closure($0)
            })
            .store(in: &subscriptions)
    
    }

Вот моя будущая фабрика:

    func futureUpcomingNotificationRequests(notificationCenter: UNUserNotificationCenter = UNUserNotificationCenter.current()) -> Future<[UNNotificationRequest], Never> {
        Future<[UNNotificationRequest], Never> { promise in
            print("Original")
            notificationCenter.getPendingNotificationRequests { requests in
                    promise(.success(requests))
            }
        }
    }

Вот моя функция для преобразования [UNNotificationReuqest] в [Date] s

    func notificationRequestsToDates(notificationRequests: [UNNotificationRequest]) ->  [Date] {
        var arrayOfDates: [Date] = []
        for request in notificationRequests {
            let realTrigger = request.trigger as? UNCalendarNotificationTrigger
            arrayOfDates.append((realTrigger?.nextTriggerDate())!)
        }
    //    return notificationRequest.trigger as! UNCalendarNotificationTrigger
        return arrayOfDates
    }

Несмотря на то, что то, что находится в теле моей updateNotificationView функции, почти идентично тому, что находится в исходной кнопке, она не обновляет массив View. В будущем функция updateNotificationView даже не инициализирует (?, запускает?), И я не уверен, почему.

Эта строка var subscriptions = subscriptions — ваша проблема. Эта локальная переменная будет перераспределена (что приведет к освобождению цепочки подписчиков), как только функция вернется (до завершения работы). Если вы используете свойство struct subscriptions, у вас будет утечка подписчиков. Вы должны обрабатывать все это в объекте модели, для которого может быть настроен один подписчик. Затем ваша кнопка будет запускать кнопку для запроса уведомлений и публикации их в PassthroughSubject или подобном.   —  person yangnom    schedule 03.02.2021

См. также:  iOS 13: использование нового NEHotspotConfiguration.init (ssidPrefix: String) не работает
Понравилась статья? Поделиться с друзьями:
IT Шеф
Комментарии: 1
  1. yangnom

    Проблема в том, что вы передаете subscriptions в качестве аргумента:

    func updateNotificationView(subscriptions: Set<AnyCancellable>, closure: @escaping ([Date]) -> ())
    

    Это две строчки:

    1. updateNotificationView (подписки: подписки)
    2. var subscriptions = подписки

    Приведет к созданию НОВОГО набора (после .store(in: &subscriptions)), который будет выпущен в конце области (конец updateNotificationView).

    Чтобы решить эту проблему, у вас есть два варианта:

    1. Сделайте subscriptions inout аргументом И удалите var subscriptions = subscriptions.
    2. Просто используйте свойство View subscriptions, не передавая его в качестве аргумента.
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: