SwiftUI MVVM: дочерняя модель представления повторно инициализируется при обновлении родительского представления - PullRequest
3 голосов
/ 07 апреля 2020

Я пытаюсь использовать MVVM в приложении SwiftUI, однако кажется, что модели представлений для дочерних представлений (например, в NavigationLink) переинициализируются всякий раз, когда ObservableObject наблюдается как родительским, так и дочерним. обновляется. Это приводит к сбросу локального состояния ребенка, перезагрузке сетевых данных и т. Д. c.

Я предполагаю, что это потому, что это вызывает переоценку родительского body, который содержит конструктор для * 1006. * модель представления, но я не смог найти альтернативу, которая позволила бы мне создавать модели представления, которые не живут за пределами срока действия представления. Мне нужно иметь возможность передавать данные в дочернюю модель представления от родителя.

Вот очень упрощенная площадка для того, что мы пытаемся выполнить sh, где увеличение EnvCounter.counter сбрасывает SubView.counter.

import SwiftUI
import PlaygroundSupport

class EnvCounter: ObservableObject {
    @Published var counter = 0
}

struct ContentView: View {
    @ObservedObject var envCounter = EnvCounter()

    var body: some View {
        VStack {
            Text("Parent view")
            Button(action: { self.envCounter.counter += 1 }) {
                Text("EnvCounter is at \(self.envCounter.counter)")
            }
            .padding(.bottom, 40)

            SubView(viewModel: .init())
        }
        .environmentObject(envCounter)
    }
}

struct SubView: View {
    class ViewModel: ObservableObject {
        @Published var counter = 0
    }

    @EnvironmentObject var envCounter: EnvCounter
    @ObservedObject var viewModel: ViewModel

    var body: some View {
        VStack {
            Text("Sub view")

            Button(action: { self.viewModel.counter += 1 }) {
                Text("SubView counter is at \(self.viewModel.counter)")
            }

            Button(action: { self.envCounter.counter += 1 }) {
                Text("EnvCounter is at \(self.envCounter.counter)")
            }
        }
    }
}

PlaygroundPage.current.setLiveView(ContentView())

1 Ответ

0 голосов
/ 10 мая 2020

У меня была та же проблема, ваши догадки верны, SwiftUI вычисляет все ваше родительское тело каждый раз, когда изменяется его состояние. Решение заключается в перемещении дочерней инициализации ViewModel в родительскую ViewModel, это код из вашего примера:

class EnvCounter: ObservableObject {
    @Published var counter = 0
    @Published var subViewViewModel = SubView.ViewModel.init()
}

struct CounterView: View {
    @ObservedObject var envCounter = EnvCounter()

    var body: some View {
        VStack {
            Text("Parent view")
            Button(action: { self.envCounter.counter += 1 }) {
                Text("EnvCounter is at \(self.envCounter.counter)")
            }
            .padding(.bottom, 40)

            SubView(viewModel: envCounter.subViewViewModel)
        }
        .environmentObject(envCounter)
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...