SwiftUI загружает данные в виде вкладок только один раз

#swiftui

#swiftui

Вопрос:

У меня есть простое приложение с TabView и 4 разными вкладками в нем. В моем втором представлении я хочу вызвать make API, чтобы получить больший тип данных.

Проблема у меня есть. Чтобы предотвратить множественные внутренние запросы, моя идея состояла в том, чтобы выполнить начальный вызов жизненного цикла Appear() вместо добавления его в ViewModel init() , потому что эта часть вызывается при каждом изменении TabView.

Однако отображаемый код не обновляется, если я вызываю сетевой запрос из onAppear.

Если я вызываю mockApiCall из ViewModel init(). затем данные обновляются, и представление также обновляется. Однако, как я упоминал ранее, я не хочу этого делать, потому что при каждом изменении вкладки будет много запросов

 
import SwiftUI

class TabsViewModel: ObservableObject {
    var shopView: some View {
        ViewsBuilder.makeShopView()
    }
    
    struct ViewsBuilder {
        static func makeShopView() -> some View {
            ShopView(viewModel: .init())
        }
    }
}

//To reproduce go to second tab, view is loaded, go to first tab and then again go to second one
struct TabsView: View {
    
    @ObservedObject
    var viewModel: TabsViewModel
    
    @State
    private var selection = 1
    
    var body: some View {
        TabView(
            selection: $selection) {
                Text("Tab Content 1")
                    .tabItem {
                        if selection == 1 {
                            Image(systemName: "star.fill")
                        } else {
                            Image(systemName: "star")
                        }
                        //it works if I set Image(systemName: "star.fill") instead of if statement
                    }
                    .tag(1)
                viewModel
                    .shopView
                    .tabItem {
                        if selection == 2 {
                            Image(systemName: "star.fill")
                        } else {
                            Image(systemName: "star")
                        }
                        //it works if I set Image(systemName: "star.fill") instead of if statement
                    }
                    .tag(2)
            }
    }
}


struct ShopView: View {
    
    @ObservedObject
    var viewModel: ShopViewModel
    
    var body: some View {
        VStack {
            ForEach(viewModel.mockedUser) { user in
                Text(user.name)
            }
        }
        .onAppear() {
            viewModel.mockApiCall()
        }
        
    }
}

class ShopViewModel: ObservableObject {
    
    @Published
    var mockedUser: [TestUser] = []
    
    func mockApiCall() {
        print("API CALLED")
        DispatchQueue.main.asyncAfter(deadline: .now()   1.0) {
            self.mockedUser = [
                TestUser(id: 1, name: "Test"),
                TestUser(id: 2, name: "User2")
            ]
        }
    }
    
    struct TestUser: Identifiable {
        let id: Int
        let name: String
    }
}


 

Комментарии:

1. Он все равно должен работать, вызывая api из onAppear. Я запустил ваш код на iOS 14.2, и он работает.

2. Отлично работает с Xcode 12.1 / iOS 14.1. Я предполагаю, что проблема в каком-то другом коде. Не могли бы вы подробнее рассказать?

Ответ №1:

Не удалось найти правильное решение, поэтому решил продолжить с аннотацией StateObject для моделей просмотра