1

I am a newbie to SwiftUI but making reasonable progress. I am using the latest version of Xcode 12.4 and running BigSur 11.2.1. I am at the stage where I want to use core-data but have run into an issue that I can't find a fix.

When I create the basic Xcode project I select App and macOS as the template Then I select Interface - SwiftUI, Life Cycle - SwiftUI App, Language - Swift and select Use Core Data

A new project is created and Builds and Runs without any issues. In the window that appears I can add a new item (a datestamp) by simply clicking the + Button on the top bar. So far so good. This is all vanilla apple code.

Where I am stuck :- The List - ForEach View in the ContentView won't allow any of the Entities (items) to be selected by clicking and therefore I can't find a way to delete an entry.

If I replace the Entities with an array of Text items then I can select them and delete them by using @State var selectKeeper = Set() with a selection: $selectKeeper in the List View.

Can someone please explain how to do it?

This is the vanilla code for the content view.

import SwiftUI
import CoreData

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

    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
        animation: .default)
    private var items: FetchedResults<Item>

    var body: some View {
        List {
            ForEach(items) { item in
                Text("Item at \(item.timestamp!, formatter: itemFormatter)")
            }
            .onDelete(perform: deleteItems)
        }
        .toolbar {
            Button(action: addItem) {
                Label("Add Item", systemImage: "plus")
            }
        }
    }

    private func addItem() {
        withAnimation {
            let newItem = Item(context: viewContext)
            newItem.timestamp = Date()

            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)")
            }
        }
    }

    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            offsets.map { items[$0] }.forEach(viewContext.delete)

            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)")
            }
        }
    }
}

private let itemFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateStyle = .short
    formatter.timeStyle = .medium
    return formatter
}()

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
    }
}

1 Answer 1

1

You should add EditButton() and probably wrap all of this in NavitagionView might give you what you are looking for:

var body: some View {
    NavigationView{
        List {
            ForEach(items) { item in
                Text("Item at \(item.timestamp!, formatter: itemFormatter)")
            }
            .onDelete(perform: deleteItems)
        }
        .toolbar {
            ToolbarItem(placement: .navigationBarLeading) {
                #if os(iOS)
                EditButton()
                #endif
            }

            ToolbarItem(placement: .navigationBarTrailing) {
                Button(action: addItem) {
                Label("Add Item", systemImage: "plus")
                }
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for responding. I did manage to get the delete working using the NavigationViews inbuilt .ondelete function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.