UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: SwiftUI Preview Crashes with CoreData

Forums > SwiftUI

Hi guys,

Here is the code:

import SwiftUI

struct ContentView: View {
    @Environment(\.managedObjectContext) var moc

    @FetchRequest(sortDescriptors: [
        SortDescriptor(\.date, order: .reverse),
        SortDescriptor(\.title)
    ]) var notes: FetchedResults<Note>

    let relativeDateTimeFormatter = RelativeDateTimeFormatter()

    @State private var showingAlert = false
    @State private var noteTitle = ""
    @State private var noteDescription = ""
    @State private var navigateToNoteView = false

    var body: some View {
        NavigationStack {
            List {
                ForEach(notes) { note in
                    NavigationLink {
                        NoteView(note: note)
                    } label: {
                        HStack {
                            VStack(alignment: .leading) {

                                Text(note.wrappedTitle)
                                    .font(.title2)

                                Text(note.wrappedDescription)
                                    .font(.caption)
                            }

                            Spacer()
                            Text(relativeDateTimeFormatter.localizedString(for: note.wrappedDate, relativeTo: Date()))
                                .font(.caption)
                                .italic()

                        }
                    }

                }
                .onDelete { offsets in
                    DataController().deleteNote(at: offsets, moc: moc, notes: Array(notes))
                }
            }
            .alert("New note", isPresented: $showingAlert) {
                TextField("Note title", text: $noteTitle)
                TextField("Note description", text: $noteDescription)

                Button("Cancel") { showingAlert = false }
                Button("Ok") {
                    if noteTitle.isEmpty || noteDescription.isEmpty {
                        return
                    } else {
                        DataController().addNote(moc: moc, title: noteTitle, description: noteDescription, text: "")
                        noteTitle = ""
                        noteDescription = ""
                        navigateToNoteView = true
                    }
                }
            }
            .navigationTitle("Notes")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button {
                        showingAlert = true
                    } label: {
                        Image(systemName: "square.and.pencil")
                    }
                }
                ToolbarItem(placement: .navigationBarLeading) {
                    EditButton()
                }
            }
            .navigationDestination(isPresented: $navigateToNoteView) {
                let note = DataController().getLastNote(moc: moc)
                NoteView(note: note ?? DataController.exampleNote)
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var dataController = DataController()
    static var previews: some View {
        Group {
            ContentView()
            ContentView()
                .preferredColorScheme(.dark)
        }
        .environment(\.managedObjectContext, dataController.container.viewContext)
    }
}

I know that the line that trigger the crash of the preview is this: NoteView(note: note ?? DataController.exampleNote) used in NavigationDestination.

Do you know how to solve?

Thanks

2      

Have you tried setting breakpoints to see where it's crashing?

2      

@deirdresm Yes, it crashes in this line: NoteView(note: note ?? DataController.exampleNote).

I tried to comment it and it works fine without crashing. But I don't know why...

2      

hi,

the thing that sticks out to me is that you are not making calls to a fixed DataController that was passed in, say, through the environment. rather, all your calls have the form

DataController().doSomething( ... )

which means that every such call creates its own instance of a DataController.

for example, the statement

DataController().addNote(moc: moc, title: noteTitle, description: noteDescription, text: "")

creates a new data controller, adds a new note, and then this instance of a data controller goes away.

similarly, i would think that

let note = DataController().getLastNote(moc: moc)

always returns a nil value, since a new data controller instance has (probably) no notes.

(i can't tell exactly what DataController.exampleNote is for the case that note is nil.)

hope that helps,

DMG

2      

Hacking with Swift is sponsored by RevenueCat.

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.