0

Watched Paul Hudson long SwiftData Tutorial and wanted to modify it by putting in the built-in ContentUnavailableView.search “No Search Results” view and also a custom “ContentUnavailableView” when there are no physical records/objects in SwiftData Person class to start. This custom View has an "add" button.

Got it working by using a computed property private var allPeople: Int that gives me the count and then if-else to make the decision. Is there another or better way of grabbing this "Person" count and is this the proper way to branch based on this count using .onAppear? I have seen .overlay used but wasn't sure which was the proper design method.

Whatever I use to keep track of the count in ContentView, I need to send into PeopleView so I can update the count if I delete someone in there.

Still learning and thanks,

Scott

struct ContentView: View {
    @Environment(\.modelContext) var modelContext
    
    @State private var destPath = NavigationPath()
    @State private var sortOrder = [SortDescriptor(\Person.name)]
    @State private var searchText = ""
    
    // Current "Person" count
    @State private var personCount = 0
    
    // TEST - Finding the total object count for Person and see if I could keep it updated in this view
    private var allPeople: Int {
        let decriptor = FetchDescriptor<Person>(predicate: #Predicate { !$0.name.isEmpty })
        return (try? modelContext.fetchCount(decriptor)) ?? 0
    }
        
    var body: some View {
        NavigationStack(path: $destPath) {
            Group {
                if personCount > 0 {
                    PeopleView(searchString: searchText, weHavePeople: $personCount, sortOrder: sortOrder)
                        .navigationTitle("Face Facts Man: \(personCount)")
                        .toolbar {
                            Menu("Sort", systemImage: "arrow.up.arrow.down") {
                                Picker("Sort", selection: $sortOrder) {
                                    "
                                    "
                                }
                            }
                            
                            Button("Add Person", systemImage: "plus", action: addPerson)
                        }
                        .searchable(text: $searchText, prompt: "Find Some People...")   
                } else {
                    ContentUnavailableView(label: {
                        Label("You Must Know Someone", systemImage: "list.bullet.rectangle.portrait")
                    }, description: {
                        Text("ContentView: Go ahead, add some people! \(personCount)")
                    }, actions: {
                        Button("Add A Person", systemImage: "person.badge.plus", action: addPerson)
                            .buttonStyle(.borderedProminent)
                    })
                }
            }
            .navigationDestination(for: Person.self) { chosenPerson in
                EditPersonView(person: chosenPerson, navPath: $destPath)
            }
            // TEST: Put in to see if the count was updating and assign so that we can branch above in Group
            .onAppear {
                personCount = allPeople
            }
        }
    }
    
    /*
     Creates the new person and inserts it as "blank" into context.  Then change the destPath
     to the correct Person we are going to edit.  It's now binded and auto-saving is now done as
     fields are changed on edit screen.
    */
    func addPerson() {
        let newPerson = Person(name: "", emailAddress: "", details: "")
        modelContext.insert(newPerson)
        destPath.append(newPerson)
    }
}
2
  • Not exactly sure what you mean but why not move the fetchCount related code into a function and then call that function whenever you need to update your count property. Commented Jul 7 at 11:12
  • Joakim - Sorry for not being completely clear. Was curious if SwiftData had a better way to get the count. And if using .onAppear was the proper way to update that count early enough so that my if-else would branch to show the rows PeopleView returns or puts up my custom ContentUnavailableView view. The only reason I am passing the count into PeopleView is so I can update it if I delete someone. Commented Jul 8 at 5:29

0

Browse other questions tagged or ask your own question.