So this project is pretty straightforward. I have an item. The use can create, get a closer look at, delete, or edit an item. For some reason, no matter how many different ways I try to do it, the edit part does not work. I've tried moving the sheet outside of the context menu (it only opens the bottom item), I've tried moving it under the list using the first index of the item (it crashes), and finally I've tried it the shown way and it just doesn't do anything. If anyone can come up with a better way to open the edit view for the correct item (preferably using a context menu, but something similar is acceptable) I would really appreciate it.
I've provided the project for a better understanding of what I'm trying to do. If you have any questions just leave a comment.
Any help would be greatly appreciated.
Content View:
struct ContentView: View {
@Environment(\.managedObjectContext) var managedObjContext
@ObservedObject var persistence = PersistenceController.shared
@State private var items = PersistenceController.shared.getItems()
@State private var showingEditView = false
@State private var showingAddView = false
var body: some View {
NavigationView{
List{
Section(""){
ForEach(items) { item in
NavigationLink(destination: ItemView(item: item)){
Text(item.name!)
}
.contextMenu{
Button(action: {
self.showingEditView.toggle()
}){
Text("Edit Item")
}
.sheet(isPresented: $showingEditView){
EditItemView(item: item)
.onDisappear(perform: {
items = persistence.getItems()
})
}
}
}
.onDelete(perform: { indexSet in
deleteItem(indexSet: indexSet)
})
}
}
.listStyle(InsetGroupedListStyle())
.cornerRadius(10)
.navigationBarTitle("My Items")
.navigationBarItems(trailing: addButton)
.onAppear(perform: {
items = persistence.getItems()
})
.sheet(isPresented: $showingAddView){
AddItemView()
.onDisappear(perform: {
items = persistence.getItems()
})
}
}
}
var addButton: some View {
Button(action: {
showingAddView.toggle()
}){
Text("Add an Item").bold()
}
}
func deleteItem(indexSet: IndexSet){
withAnimation{
indexSet.map {
items[$0]
}
.forEach(managedObjContext.delete)
persistence.contextSave()
items = persistence.getItems()
}
}
}
Item View:
struct ItemView: View{
@State var item: Item
var body: some View{
Text(item.name ?? "No Name")
}
}
Add View:
struct AddItemView: View{
@Environment(\.dismiss) var dismiss
@ObservedObject var persistence = PersistenceController.shared
@State private var name = ""
var body: some View {
Form{
TextField("Item Name", text: $name)
Button(action:{
persistence.addItem(name: name)
dismiss()
}){
Text("Add Item")
}
}
}
}
Edit View:
struct EditItemView: View{
@Environment(\.dismiss) var dismiss
@ObservedObject var persistence = PersistenceController.shared
@State var item: Item
@State private var name = ""
var body: some View {
Form{
TextField("Item Name", text: $name)
Button(action:{
persistence.addItem(name: name)
dismiss()
}){
Text("Add Item")
}
}
.onAppear{
name=item.name ?? "No Name"
}
}
}
Persistence File:
class PersistenceController : ObservableObject{
static let shared = PersistenceController()
let container: NSPersistentContainer
init(inMemory: Bool = false) {
container = NSPersistentContainer(name: "Test")
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
}
static var preview: PersistenceController = {
let result = PersistenceController(inMemory: true)
let viewContext = result.container.viewContext
for _ in 0..<10 {
let newItem = Item(context: viewContext)
newItem.id = UUID()
newItem.name = "Test"
}
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
return result
}()
func getItems() -> [Item] {
let context = container.viewContext
var request = NSFetchRequest<Item>()
request = Item.fetchRequest()
request.entity = NSEntityDescription.entity(forEntityName: "Item", in: context)
do {
let items = try context.fetch(request)
if items.count == 0 { return []}
return items.sorted(by: {$0.name! > $1.name!})
} catch {
print("**** ERROR: items fetch failed \(error)")
return []
}
}
func addItem(name: String){
let context = container.viewContext
let item = Item(context: context)
item.id = UUID()
item.name = name
contextSave()
}
func contextSave() {
let context = container.viewContext
if context.hasChanges {
do {
try context.save()
self.objectWillChange.send()
} catch {
print("**** ERROR: Unable to save context \(error)")
}
}
}
}
Data Model: