SwiftUI(Core Data) - Xcode Preview stops, but does not crash

78 views Asked by At

Although Xcode does not give me any information, I assumed that it is related to Core Data because it started since I changed codes related to Core Data.

This is what happens.

My Code

I have many codes in my project, and I cannot show you the whole code because of word limit. But I can show the core of my project.

ContentView - includes two tab views(VocabularyFolderView and QuizHome View)

import SwiftUI

struct ContentView: View {
    var body: some View {
        TabView {
            VocabularyFolderView()
                .tabItem {
                    Label("Vocabulary", systemImage: "list.dash")
                }

            QuizHomeView()
                .tabItem {
                    Label("Quiz", systemImage: "questionmark.app")
                }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        //ForEach(["iPhone SE (3nd generation)", "iPhone 13", "iPad Pro (11-inch) (1st generation)", "iPad Air (3rd generation)", "iPad Air (4th generation)"], id: \.self) { deviceName in
            //ContentView()
                //.environment(\.managedObjectContext, PersistenceController.VocabularyFolder_Preview.container.viewContext)
                //.previewDevice(PreviewDevice(rawValue: deviceName))
                //.previewDisplayName(deviceName)
        //}
        ContentView()
            .environment(\.managedObjectContext, PersistenceController.VocabularyFolder_Preview.container.viewContext)
            .previewInterfaceOrientation(.portrait)
    }
}

VocabularyFolderView - It is a NavigationView that contains a list of Core Data entities

import SwiftUI
import CoreData

struct VocabularyFolderView: View {
    @Environment(\.managedObjectContext) private var managedObjectContext

    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \FolderStruct.name, ascending: true)],
        animation: .default)
    private var folders: FetchedResults<FolderStruct>
    
    @State private var showAddView: Bool = false
    @State private var showAddErrorAlert: Bool = false
    @State private var showDeleteErrorAlert: Bool = false
    
    @State private var showFavoritesOnly = false
    
    var filteredFolders: [FolderStruct] {
        folders.filter { folder in
            (!showFavoritesOnly || folder.starred)
        }
    }
    
    var body: some View {
        NavigationView {
            List {
                Section {
                    Toggle(isOn: $showFavoritesOnly) {
                        Text("Favorites only")
                    }
                }
                
                Section {
                    ForEach(filteredFolders) { folder in
                        NavigationLink {
                            VocabularyListView(parentFolder: folder)
                        } label: {
                            HStack {
                                Image(systemName: "folder")
                                    .foregroundColor(.accentColor)
                                    .listRowSeparator(.hidden)
                                
                                Text(folder.name ?? "")
                                
                                Spacer()
                                
                                Text("\(folder.childlists!.count)")
                                    .foregroundColor(.secondary)
                                
                                if folder.starred {
                                    Image(systemName: "star.fill")
                                        .foregroundColor(.yellow)
                                } else {
                                    Image(systemName: "star")
                                        .foregroundColor(.gray)
                                }
                            }
                        }
                        .swipeActions(edge: .leading) {
                            Button {
                                deleteFolder(folder: folder)
                            } label: {
                                Label("Pin", systemImage: "pin.fill")
                            }
                            .tint(.orange)
                        }
                        .swipeActions(edge:. trailing, allowsFullSwipe: false) {
                            Button(role: .destructive) {
                                deleteFolder(folder: folder)
                            } label: {
                                Label("Delete", systemImage: "trash.fill")
                            }
                        }
                    }
                }
            }
            .navigationTitle("Folders")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
                
                ToolbarItem(placement: .bottomBar) {
                    HStack {
                        Button(action: addItem) {
                            Label("Add Item", systemImage: "folder.badge.plus")
                        }
                        
                        Spacer()
                    }
                }
            }
            .sheet(isPresented: $showAddView) {
                AddFolderView()
            }
            //alert(isPresented: $showAddView,
            //    TextAlert(title: "New Folder", message: "Message") { result in
            //        if let text = result {
            //        // Text was accepted
            //        } else {
            //        // The dialog was cancelled
            //        }
            //    })
            .alert("Error while deleting a word", isPresented: $showDeleteErrorAlert) {
                Button("OK", role: .cancel) { }
            }
            .alert("Error while adding a word", isPresented: $showAddErrorAlert) {
                Button("OK", role: .cancel) { }
            }
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
    
    
    
    private func addItem() {
        showAddView = true
    }
    
    private func deleteFolder(folder: FolderStruct) {
        managedObjectContext.delete(folder)

        do {
            try managedObjectContext.save()
        } catch {
            showDeleteErrorAlert = true
            
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
    }
}

struct VocabularyFolderView_Previews: PreviewProvider {
    static var previews: some View {
        VocabularyFolderView().environment(\.managedObjectContext, PersistenceController.VocabularyFolder_Preview.container.viewContext)
    }
}

QuizHomeView

import SwiftUI
import CoreData

struct QuizHomeView: View {
    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \FolderStruct.name, ascending: true)],
        animation: .default)
    private var folders: FetchedResults<FolderStruct>
    
    @State private var showingSheet = false
    @State private var quizType = "단어 뜻 맞추기"
    @State private var folderSelection: FolderStruct?
    @State private var listSelection = "단어장 선택"
    
    let quizTypes = ["단어 뜻 맞추기", "원래 단어 맞추기"]
    
    var body: some View {
        NavigationView {
           Form {
               Section {
                   Picker("Quiz Type", selection: $quizType) {
                        ForEach(quizTypes, id: \.self) {
                            Text($0)
                        }
                   }
                   .pickerStyle(.segmented)
               }

               Section {
                   Picker("폴더 선택", selection: $folderSelection) {
                       ForEach(folders) { (folder: FolderStruct) in
                           Text(folder.name!)
                       }
                   }
                   
                   //Picker("단어장 선택", selection: $listSelection) {
                   //    ForEach(listSelections, id: \.self) {
                    //       Text($0)
                   //    }
                   //}
               }
               
               Section {
                   Button("시작하기") {
                       showingSheet.toggle()
                       
                   }
                   .disabled(folderSelection == nil || listSelection.isEmpty || listSelection == "단어장 선택")
               }
           }
           .navigationTitle("퀴즈")
           .sheet(isPresented: $showingSheet) {
               QuizPlayView()
           }
        }
    }
}
    

struct QuizHomeView_Previews: PreviewProvider {
    static var previews: some View {
        QuizHomeView()
    }
}

Persistence.swift

import CoreData
import Foundation

struct PersistenceController {
    static let shared = PersistenceController()

    static var VocabularyFolder_Preview: PersistenceController = {
        let result = PersistenceController(inMemory: true)
        let viewContext = result.container.viewContext
        
        var previewString = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
        for i in previewString {
            let newFolder = FolderStruct(context: viewContext)
            newFolder.name = i
            newFolder.starred = true
        }
        do {
            try viewContext.save()
        } catch {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
        return result
    }()
    
    static var AddFolder_Preview: PersistenceController = {
        let result = PersistenceController(inMemory: true)
        let viewContext = result.container.viewContext
        
        let newFolder = FolderStruct(context: viewContext)
        newFolder.name = "Example Folder"
        newFolder.starred = true

        do {
            try viewContext.save()
        } catch {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
        return result
    }()
    
    static var VocabularyList_Preview: PersistenceController = {
        let result = PersistenceController(inMemory: true)
        let viewContext = result.container.viewContext
        
        var previewString = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
        for i in previewString {
            let parentFolder = FolderStruct(context: viewContext)
            parentFolder.name = i
            parentFolder.starred = true
            
            let newList = ListStruct(context: viewContext)
            newList.name = i
            newList.starred = true
            newList.parentfolder = parentFolder
        }
        do {
            try viewContext.save()
        } catch {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
        return result
    }()
    
    static var AddList_Preview: PersistenceController = {
        let result = PersistenceController(inMemory: true)
        let viewContext = result.container.viewContext

        let parentFolder = FolderStruct(context: viewContext)
        parentFolder.name = "Example Folder"
        parentFolder.starred = true
        
        let newList = ListStruct(context: viewContext)
        newList.name = "Example List"
        newList.starred = true
        newList.parentfolder = parentFolder

        do {
            try viewContext.save()
        } catch {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
        return result
    }()
    
    static var Vocabulary_Preview: PersistenceController = {
        let result = PersistenceController(inMemory: true)
        let viewContext = result.container.viewContext
        
        let previewString = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
        for i in previewString {
            let parentList = ListStruct(context: viewContext)
            parentList.name = i
            parentList.starred = true
            
            let newVocabulary = VocabularyStruct(context: viewContext)
            newVocabulary.word = i
            newVocabulary.meaning = i
            newVocabulary.starred = true
            newVocabulary.parentlist = parentList
        }
        do {
            try viewContext.save()
        } catch {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
        return result
    }()
    
    static var AddVocabulary_Preview: PersistenceController = {
        let result = PersistenceController(inMemory: true)
        let viewContext = result.container.viewContext

        let parentList = ListStruct(context: viewContext)
        parentList.name = "Example List"
        parentList.starred = true
        
        let newVocabulary = VocabularyStruct(context: viewContext)
        newVocabulary.word = "Example Word"
        newVocabulary.meaning = "Example Meaning"
        newVocabulary.starred = true
        newVocabulary.parentlist = parentList

        do {
            try viewContext.save()
        } catch {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
        return result
    }()
    
    static var FolderStruct_Preview: FolderStruct {
        let folder = FolderStruct()
        folder.name = "Example Folder"
        folder.starred = true
        
        return folder
    }
    
    static var ListStruct_Preview: ListStruct {
        let list = ListStruct()
        list.name = "Example List"
        list.starred = true
        list.parentfolder = FolderStruct_Preview
        
        return list
    }
    
    static var VocabularyStruct_Preview: VocabularyStruct {
        let vocabulary = VocabularyStruct()
        vocabulary.word = "Example Word"
        vocabulary.meaning = "Example Meaning"
        vocabulary.starred = true
        vocabulary.parentlist = ListStruct_Preview
        
        return vocabulary
    }
    
    let container: NSPersistentCloudKitContainer

    init(inMemory: Bool = false) {
        container = NSPersistentCloudKitContainer(name: "Vocabulary")
        if inMemory {
            container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
        }
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
    
                /*
                 Typical reasons for an error here include:
                 * The parent directory does not exist, cannot be created, or disallows writing.
                 * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                 * The device is out of space.
                 * The store could not be migrated to the current model version.
                 Check the error message to determine what the actual problem was.
                 */
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        container.viewContext.automaticallyMergesChangesFromParent = true
    }
}
0

There are 0 answers