#swift #navigation #swiftui
#swift #навигация #swiftui
Вопрос:
Я хочу, чтобы мой @StateObject
деинициализировался как можно скорее после перехода назад, но кажется, что объект хранится в памяти. «Deint ViewModel» не печатается при обратной навигации, он сначала печатается после того, как я снова перейду к представлению, из которого я исходил. Есть ли способ освободить @StateObject
из памяти при обратной навигации?
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination: TestView(), label: { Text("Show Test View") })
}
}
}
struct TestView: View {
@StateObject private var viewModel = ViewModel()
var body: some View {
Text("Test View")
}
}
final class ViewModel: ObservableObject {
deinit {
print("Deint ViewModel")
}
}
Ответ №1:
У меня нет блестящего ответа на все ситуации, которые препятствуют деинициализации @StateObject, но я обнаружил, что выполнение фоновых асинхронных задач предотвращает деинициализацию.
В моем случае у меня было зарегистрировано несколько отменяемых объектов для прослушивания PassthroughSubject и / или CurrentValueSubject (которые я использовал для обработки внешних изменений в моей модели и отображения результата в представлении), но я никогда не отменял их. Как только я сделал это в представлении, используя .onDisappear, это сработало.
Итак, все мои представления «подписываются» на модель представления (у меня есть метод ViewModel.subscribe()) с использованием .onAppear, а затем «отписываются» от модели представления (у меня есть метод ViewModel.subscribe()) с использованием .onDisappear. При этом @StateObject деинициализируется при отклонении представления.
Ответ №2:
Добавление к ответу GregP: если вы удалили все свои cancellables
on onDisappear
и deinit
все еще не вызываетесь, вы можете использовать график памяти отладки
Перейдите к объекту, посмотрите его дерево и посмотрите, что еще ссылается на него. Например, у меня это выглядело так:
Поскольку на этот объект ссылался другой объект, он не удалялся из памяти (ARC). Итак, все, что мне нужно было сделать, это удалить его из статуса делегата вместе с отменой cancellables
вызова and deinit
Ответ №3:
Я думаю, вам следует использовать @ObservedObject private var viewModel: ViewModel
вместо этого, а затем ввести новый экземпляр ViewModel извне testView
Комментарии:
1. Можете ли вы объяснить мне, как это поможет отключить ViewModel при переходе назад? Реальная проблема заключается в том, что при переходе назад testView все еще находится в памяти, поэтому ViewModel не деинициализируется, когда ожидалось. Я просто думаю, что это «особенность» NavigationView.
2. Если вы используете
StateObject
, ваша модель представления не будет уничтожена. вместо этого используйте observedObject . вы можете проверить donnywals.com /… чтобы более четко3. Вызывается деинит объекта состояния. На данный момент я сталкиваюсь с проблемой, когда он не вызывается, у меня все еще есть некоторые вызовы async / await, запущенные на нем, но, если я этого не сделаю, де-инициализация вызывается в ViewModel.