0
votes

I have a sheet which displays a guide for my app. the sheet isPresented by a local bool showingGuide. I want that local bool to mirror a bool in Core Data in my settings entity with the bool showGuide

I know how to save and retrieve the state of the bool in general but retrieving the bool in core data on app launch is where i'm getting stuck.

When the user hits the button 'Got it!' I'm wanting the guide to never show again. (Maybe i might setup a button in the settings view that can activate it again if they need a refresher)

I've tried playing with a custom initialiser of the Test view that tries to retrieve settings.showGuide but have had no luck.

I also understand that settings is an array so i'll have to always save and retrieve into first item in the settings array. Is there an easier way to do that? save one entity instead of an array?

Any ideas?

import Foundation
import SwiftUI
import CoreData


struct Test: View {

    @Environment(\.managedObjectContext) var managedObjectContext
    @FetchRequest(fetchRequest: Settings.getSettings()) var settings:FetchedResults<Settings>

    @State private var showingGuide = true

    var body: some View{

        VStack{
            Text("Hello")
        }
        .sheet(isPresented: $showingGuide) {

            MainGuide().padding(.horizontal)

            Button(action: {
                let settings = Settings(context: self.managedObjectContext)
                settings.showGuide = false
                self.showingGuide = false
                do {
                    try self.managedObjectContext.save()
                }catch{
                    print(error)
                }
            }){
                Text("Got it!")

            }.padding()
        }
    }


}

enter image description here

CoreData

1

1 Answers

0
votes

Your are not supposed to set a @State-variable programatically (link). Instead, use an if-statement that depends on the boolean from your CoreData-object to display the sheet or not.

I also recommend to add a computed variable for the settings object as it is always the first element in the array as shown in the code below for var settings.

You can do it like this:

struct ContentView: View {

    @Environment(\.managedObjectContext) var managedObjectContext

    @FetchRequest(
        entity: Settings.entity(),
        sortDescriptors: [
            NSSortDescriptor(keyPath: \Settings.self, ascending: false)
        ]
    ) var settingsRequest: FetchedResults<Settings>

    var settings:Settings{
        settingsRequest[0]
    }

    @State var showGuide:Bool = true

    var body: some View{
        VStack{
            if settings.showSheet{
                Text("show sheet: \(String(settings.showSheet))").sheet(isPresented: $showGuide){
                    Text("Hello from Sheet")
                    Button(action: {
                        self.settings.showSheet = false
                        self.showGuide = false
                        do {
                            try self.managedObjectContext.save()
                        }catch{
                            print(error)
                        }
                    }){
                        Text("Got it!")

                    }.padding()
                }
            }else{
                Text("already agreed")
            }
        }
    }
}

Note: This will only set settings.showSheet to true if the user click on the button. When dismissing the sheet by swiping, it will not update CoreData. If you want to perform some action on the swiping action, you could use .onDismiss(perform: { }).