Как слушать ObservableObject - PullRequest
       7

Как слушать ObservableObject

1 голос
/ 22 января 2020

Хорошо, поэтому SwiftUI и ObservableObject, на iOS 13. У меня есть Модель, которая реализует ObservableObject:

class Model: ObservableObject {
    @Published public var toggle: Bool = false

    init() {
        NSLog("Model init")
        objectWillChange.sink { void in
            NSLog("1 toggle \(self.toggle)")
        }
        $toggle.sink { v in
            NSLog("2 toggle \(self.toggle) -> \(v)")
        }
    }
}

и Кнопка, которая переключает toggle:

struct ContentView: View {
    @ObservedObject var model: Model

    var body: some View {
        Button(action: {
            self.model.toggle.toggle()
        }, label: {Text(model.toggle ? "on" : "off")})
    }
}

Теперь это работает. Вы нажимаете кнопку, и она переключается между «вкл» и «выкл». (Прежде чем сделать toggle @Published, это не так.) Однако ведение журнала не работает должным образом. Я получаю два журнала сразу при запуске: «Модель инициализации» и «2 переключения ложь -> ложь». Нажатие на кнопку, хотя и явно изменяющее значение toggle, не приводит к выполнению любого из замыканий.

Когда представление изменяет вашу модель, я ожидаю, что будет способ получить информацию о изменение, если вам нужно, например, обновить вычисленные значения или syn c на диск или что-то еще. Возможно, sink неправильный метод?

Как можно уведомить ObservableObject с полями @Published, когда его поля обновляются?

Ответы [ 2 ]

2 голосов
/ 22 января 2020

Последняя документация для возвращаемого значения функции sync:

/// - Returns: A cancellable instance; used when you end assignment of the received value. Deallocation of the result will tear down the subscription stream.

По сути, это означает, что приемник создает Subscriber, но не сохраняет его. Как только ваша инициализация завершена, подписчики срываются и удаляются из памяти. Вы должны держать их рядом, создавая сильную ссылку, подобную этой:

class Model: ObservableObject {
    @Published public var toggle: Bool = false

    var changeSink: AnyCancellable?
    var toggleSink: AnyCancellable?

    init() {
        NSLog("Model init")
        changeSink = objectWillChange.sink { void in
            NSLog("1 toggle \(self.toggle)")
        }
        toggleSink = $toggle.sink { v in
            NSLog("2 toggle \(self.toggle) -> \(v)")
        }
    }
}

Я не использовал много Combine, но альтернативу, которую я часто видел, вы могли бы рассмотреть, просто добавление didSet к вашему атрибуту так:

    @Published public var toggle: Bool = false {
        didSet {
            print("1 toggle \(self.toggle)")
        }
    }
1 голос
/ 22 января 2020

Ваш класс ObservableObject Модель выполнена правильно, но:

1. ObjectWillChange должен иметь тип ObservableObjectPublisher () .

, который создает свойство objectWillChange как экземпляр ObservableObjetPublisher. Это происходит из фреймворка Combine, поэтому вам нужно добавить импорт Combine для компиляции кода. Работа издателя наблюдаемых объектов проста: всякий раз, когда мы хотим рассказать миру, что наш объект изменился, мы просим издателя сделать это за нас.

2. свойство, которое вы должны наблюдать (Toggle), должно быть реализовано следующим образом:

 var toggle = "" {
        willSet {
            objectWillChange.send()
        }
    }

Во-вторых, у нас есть наблюдатель свойства willSet, присоединенный к свойству Toggle модели, чтобы мы могли запустить код всякий раз, когда это значение меняется. В нашем примере кода мы вызываем objectWillChange.send () всякий раз, когда изменяется тумблер, и именно поэтому издатель objectWillChange сообщает о том, что наши данные изменились, поэтому любые подписанные представления могут обновлять sh.

* 1020. *

3. убедитесь, что ваш класс Model соответствует ObservableObject, а его экземпляр помечен @ ObservedObject

Поскольку ваш класс Model соответствует ObservableObject, вы можете использовать его так же, как любое другое свойство @ObservedObject. Таким образом, мы можем использовать его для наблюдения за переключением, например:

struct ContentView: View {
    @ObservedObject var model: Model

    var body: some View {
        Button(action: {
            self.model.toggle.toggle()
        }, label: {Text($model.toggle ? "on" : "off")})
    }
}

Надеюсь, это поможет, ссылка: https://www.hackingwithswift.com/quick-start/swiftui/how-to-send-state-updates-manually-using-objectwillchange

...