Reputation: 327
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