BLACK FRIDAY: Save 50% on all my Swift books and bundles! >>

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      

Save 50% in my WWDC sale.

SAVE 50% All our books and bundles are half price for Black Friday, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.