SwiftUI View с @State, который инициализируется в конструкторе init () - PullRequest
0 голосов
/ 26 февраля 2020

У меня есть такая простая галочка SwiftUI view. Он отображается в списке и может переключаться нажатием на него или переключаться при обновлении из источника данных (например, Core Data)

Моя первая реализация была

struct RoundedCheckmark: View {

    @State var isChecked : Bool
    let onCheck: (Bool) -> Void

    func toggle() { isChecked = !isChecked; onCheck(isChecked) }

    init(isChecked: Bool, onCheck: @escaping (Bool) -> Void = { _ in }) {
        self._isChecked = State(initialValue: isChecked)
        self.onCheck = onCheck
    }

    var body: some View {

        Button(action: toggle) {

            Image(isChecked ? "CheckedCheckmark" : "UncheckedCheckmark")
        }
    }
}

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

Но после внешних обновлений, таких как pu sh, обновление базовых моделей в Базовых данных при обновлении sh этого представления неправильно изменяет свойство @State isChecked.

В init () я получаю новое значение isChecked и повторно инициализирую @State с State (initialValue:). Но в теле я получаю старое значение isChecked как из старого свойства @State. поэтому представление имеет неправильное изображение.

Это обходной путь, т. Е. Использование только свойства let isChecked и обратного вызова onCheck. Но теперь у меня не может быть состояния внутри моего View, и я должен полагаться только на изменение внешнего источника данных. Может быть, это более уместно, так как у меня есть один источник правды без локального хранилища @State.

struct RoundedCheckmark: View {

    let isChecked: Bool
    let onCheck: (Bool) -> Void

    func toggle() { onCheck(isChecked) }

    init(isChecked: Bool, onCheck: @escaping (Bool) -> Void = { _ in }) {

        self.isChecked = isChecked
        self.onCheck = onCheck
    }

    var body: some View {

        Button(action: toggle) {

            Image(isChecked ? "CheckedCheckmark" : "UncheckedCheckmark")

        }

    }
}

1 Ответ

1 голос
/ 26 февраля 2020

isChecked как @State переменная является вашим источником истины. Это означает, что при изменении какой-либо базовой модели данных (например, CoreData) это не имеет значения. Ваш взгляд только смотрит на локальную @State версию isChecked.

Но посмотрите на ваш взгляд. Для меня это не должно иметь своего собственного государства. Почему? Потому что нет semanti c, означающего это представление как представление галочки. Его родитель, кажется, владеет состоянием (следовательно, существует обратный вызов onCheck). Вместо этого следует использовать @Binding с no callback:

struct RoundedCheckmark: View {
    @Binding var isChecked: Bool

    var body: some View {
        Button(action: { isChecked.toggle() }) {
            Image(isChecked ? "CheckedCheckmark" : "UncheckedCheckmark")
        }
    }

Теперь ваш parent владеет состоянием, и вы можете вывести его semanti c значение :

struct CheckmarkOwner: View {
    @State var showFavoritesOnly = false

    var body: some View {
        // content

        RoundedCheckmark(isChecked: $showFavoritesOnly)

        // and now something else will get notified when `showFavoritesOnly` gets toggled
        if showFavoritesOnly {
             // toggleable content
        }

        // more content
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...