Search code examples
swiftuinsfetchrequest

SwiftUI - update view after adding CoreData record


When a user wants to create a new record, I'd like to a) go to a new view, b) create the record during .onAppear, and then c) have the view update using the newly created record.

The first part is easy. I have a NavigationLink that goes to the new view along with the user name as a property. And I can create a new record during .onAppear. But it's the last part where things get tricky.

I have tried to create the record and switch views with a simultaneous gesture, I've tried loading the new view with a toggle view function, and about a dozen less inspired ideas. The problem always comes down to this: How do I get the FetchRequest to update after the new record has been created? Note: I need a reference to the newly created record so that the user can add things to the record.

Here's the code so far...

struct RecordView: View {
    
    @Environment(\.managedObjectContext) var moc
    let appDelegte = UIApplication.shared.delegate as! AppDelegate
    
    var fetchedRecords: FetchRequest<Record>
    var currentUser: User
    
    init(recordNumber: String) {
        fetchedRecords = FetchRequest<Record>(entity: Record.entity(), sortDescriptors: [], predicate: NSPredicate(format: "user.recordNumber = %@", recordNumberNumber))
    }
    
    var body: some View {
        Text(fetchedRecords.wrappedValue.first.recordNumber)
        
    }
    .onAppear {
        self.CreateNewRecord()
    }
    
    func CreateNewRecord() {
        let newRecord = Record(context: self.moc)
        newRecord.id = UUID()
        let recordNumber = "AABBCCDDEE"
        
        user.addToRecords(newRecord)
        appDelegate.saveContext()

    //This is when the fetched request should fetch the new record and the Text view should be updated.
    }
}

Solution

  • What finally worked was combining a NavigationLink with a Button as explained by @kontiki. That allowed me to create a new record before going to the new view.I'm not sure this is the best solution, but it definitely works! The code below shows the theory behind the solution.

    @State private var presentMe = false
    @State var currentNumber = 10
        
        var body: some View {
            NavigationView {
                VStack {
                    NavigationLink(destination: SecondView(number: currentNumber), isActive: $presentMe) { EmptyView() }
                    
                    Button(action: {
                    //This is where I created a new record and saved to Core Data
                        self.currentNumber = 5 
                        //I was then able to pass the new record to the second view through the navigation link
                        self.presentMe = true
                    }) {
                        Text("Go to SecondView")
                    }
                }
            }
        }
    }
    
    struct SecondView: View {
        var number: Int
        
        var body: some View {
            Text("The number is now = \(number)") //The number is now = 5
        }
    }