jonathan3087
jonathan3087

Reputation: 327

Why is my @Published array getting cleared in the viewModel when I call a second swiftUI view?

I have an @Published var myAllCategories: [Category] = [], when I load my first view, I call an api to get all categories, then I call a functon called to loadMyMajorCategories which reads the myAllCategories and appends the ones I want for myMajorCategories. This all works fine, and I have a print statement that will show that the myAllCategories still has elements in it after this.

My view changes to a new view where I want to display subCategories, so I call a function to loadMySubCategories, and I want to read my same myAllCategories array again, and I'll search for subCategoreis and append them to the mySubCategoreis array.

The problem is nothing is found, so I tried just appending all the records with no selection, still nothing.

So now I just put a print statement to display what is in the myAllCategories array, and I get an index Out of Bounds, because I attempted to access elements in the array but the array is empty.

How can my array be empty, it just had records in it when I called the loadMyMajorCategories()?

Is there something that is keeping the myAllCategories from persisting?

Here's the view model and the two views

import Foundation
import SwiftUI

@MainActor
class CategoryViewModel: ObservableObject {
    @Published var path = NavigationPath()
    @Published var myAllCategories: [Category] = []
    @Published var myMajorCategories: [Category] = []
    @Published var mySubCategories: [Category] = []
    
    // Alert vars
    @Published var alertTitle = ""
    @Published var alertMessage = ""
    @Published var showApiAlert = false
    
    // MARK: - Categories
    func loadCategories() async {
        Service.sharedInstance.getCategoriesApi { categories in
            self.myAllCategories = categories.subcategories
            self.loadMyMajorCategories()
        } failure: { alertType, errorText in
        }
    }
    
    func loadMyMajorCategories() {
        for major in myAllCategories {
            if major.categoryLevel == 1 {
                myMajorCategories.append(major)
            }
        }
        print("🪵 loadMajorCategories allCategories first element: \(myAllCategories[0].majorCategory)-\(myAllCategories[0].description)")
    }
    
    func loadMySubCategories(majorCategory: Category) {
        print("🪵 filteredSubCategories() called")
        print("🪵 filteredSubCategories allCategories first element: \(myAllCategories[0].majorCategory)-\(myAllCategories[0].description)")
        self.mySubCategories = myAllCategories.filter({
            $0.categoryLevel == 2
        })
    }
}

Here's the view for the major categories:

import SwiftUI

struct BrowseByCategoryView: View {
    
    var backPressed: ()->()
    
    @State private var categoryName = ""
    @StateObject private var vm = CategoryViewModel()
    
    var body: some View {
        NavigationStack(path: $vm.path){
            VStack {
                MyNavigationBar(
                    title: "Major Category",
                    backgroundColor: Color("browseByCatColor"),
                    navHeight: 48,
                    backText: "More",
                    backPressed: {
                        print("🪵 BrowseByCategoryView --- backPressed() line \(#line)")
                        backPressed()
                    },
                    showAddButton: false,
                    addPressed: {}
                )
                CustomerInfoBar(backgroundColor: Color("browseByCatAccent"))
                
                List(vm.myMajorCategories, id: \.self) { category in
                    NavigationLink(destination: {
                        BrowseBySubView(majorCat: category)
                    }, label: {
                        GeometryReader { geometry in
                            Text(category.description)
                                .frame(
                                    width: geometry.size.width * 0.90,
                                    height: geometry.size.height,
                                    alignment: .leading
                                )
                                .onTapGesture(perform: {
                                    // Navigate to a list of items in this category
                                    print("🪵 Will display items in \(category.description) category")
                                    categoryName = category.description
                                    vm.path.append("BrowseItems")
                                })
                                .listRowBackground(Color(.tertiarySystemBackground))
                        }
                    })
                }
                .navigationDestination(for: String.self) { view in
                    if view == "BrowseItems" {
                        BrowseItemsView(
                            categoryName: categoryName,
                            backPressed: { backPressed()
                            })
                    }
                }
                .listStyle(.plain)
                .ignoresSafeArea()
                
                Spacer()
            }
        }
        .task {
            // Use .task to run an asynchronous task before the view appears
            await vm.loadCategories()
        }
        //MARK: API Alerts
        // This presents API errors for the entire Returns module, everything called under ReturnsListView
        .alert(vm.alertTitle, isPresented: $vm.showApiAlert) {
            Button("OK") {}
        } message: {
            Text(vm.alertMessage)
        }
    }
}

Here's the view for the sub categories:

import SwiftUI

struct BrowseBySubView: View {
    var majorCat: Category
    @Environment(\.dismiss) var dismiss
    
    @State private var categoryName = ""
    @StateObject private var vm = CategoryViewModel()
    
    var body: some View {
        NavigationStack(path: $vm.path) {
            VStack {
                MyNavigationBar(
                    title: "Sub Category",
                    backgroundColor: Color("browseByCatColor"),
                    navHeight: 48,
                    backText: "Back",
                    backPressed: {
                        print("🪵 BrowseBySubView --- backPressed() line \(#line)")
                        dismiss()
                    },
                    showAddButton: false,
                    addPressed: {}
                )
                CustomerInfoBar(backgroundColor: Color("browseByCatAccent"))
                
                Text("Test Text")
                Text("\(majorCat.majorCategory) - \(majorCat.description)")
                List(vm.mySubCategories, id: \.self) { subCat in
                    NavigationLink(destination: {
                        BrowseByMinorView(subCat: subCat)
                    }, label: {
                        GeometryReader { geometry in
                            Text(subCat.description)
                                .frame(
                                    width: geometry.size.width * 0.90,
                                    height: geometry.size.height,
                                    alignment: .leading
                                )
                                .onTapGesture(perform: {
                                    // Navigate to a list of items in this category
                                    print("🪵 Will display items in \(majorCat.description) category")
                                    categoryName = subCat.description
                                    vm.path.append("BrowseItems")
                                })
                                .listRowBackground(Color(.tertiarySystemBackground))
                        }
                    })
                
                }
                .navigationBarBackButtonHidden(true)
                .navigationDestination(for: String.self) { view in
                    if view == "BrowseItems" {
                        BrowseItemsView(
                            categoryName: categoryName,
                            backPressed: { dismiss() }
                        )
                    }
                }
                .listStyle(.plain)
                .ignoresSafeArea()
                
                Spacer()
            }
        }
        .onAppear {
        // Use .onAppear to perform an action before this view appears
            print("🪵 BrowseBySub.onAppear majorCatDescription: \(majorCat.description)")
            print("🪵 BrowseBySub.onAppear majorCategory: \(majorCat.majorCategory)")
            vm.loadMySubCategories(majorCategory: majorCat)
        }
        //MARK: API Alerts
        .alert(vm.alertTitle, isPresented: $vm.showApiAlert) {
            Button("OK") {}
        } message: {
            Text(vm.alertMessage)
        }
    }
}

Upvotes: 0

Views: 26

Answers (0)

Related Questions