Let's say that Item
is a CoreData entity:
struct ItemDetailView: View {
@Binding var item: Item?
@Binding var isEditing: Bool
var body: some View{
if isEditing {
TextField( "Name", text: Binding($item.data)! )
}else{
Text(item!.data!)
}
}
}
Error: Value of optional type 'Item?' must be unwrapped to refer to member 'data' of wrapped base type 'Item'
Edit All the code:
import SwiftUI
import CoreData
struct ItemDetailView: View {
@Binding var item: Item?
@Binding var isEditing: Bool
var body: some View{
if isEditing {
TextField( "Name", text: Binding($item.data)! )
}else{
Text(item!.data!)
}
}
}
struct ItemEditorView: View {
@Environment(\.managedObjectContext) private var viewContext
@Environment(\.dismiss) private var dismiss
let isNew: Bool
@State var isEditing: Bool = false
@State var item: Item?
@Binding var newItem: Item?
var body: some View {
if isNew {
}
NavigationView{
ItemDetailView(item: isNew ? $newItem : $item, isEditing: $isEditing)
.toolbar {
ToolbarItem {
Button(isNew ? "Add" : (isEditing ? "Done" : "Edit")) {
//TBI
if isNew {
}
}
}
ToolbarItem(placement:.cancellationAction){
Button("Cancel"){
dismiss()
}
}
}
.navigationTitle("Item Editor")
}
}
}
struct ItemsListView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item.data, ascending: true)],
animation: .default)
private var items: FetchedResults<Item>
@State var presentNewItemEditorView = false
@State var newItem: Item?
var body: some View {
NavigationView {
VStack{
Text(newItem?.data ?? "nil")
List {
ForEach(items){ item in
NavigationLink(item.data!, destination: ItemEditorView(isNew: false, item:item, newItem: $newItem))
}
}
}
.fullScreenCover(isPresented: $presentNewItemEditorView, content: {
ItemEditorView(isNew: true, isEditing: true, newItem: $newItem)
})
.navigationTitle("Main")
.toolbar {
ToolbarItem {
Button("New goal"){
presentNewItemEditorView = true
}
}
}
.task {
newItem = Item(context: viewContext)
newItem!.data = "New item text"
}
}
}
}
Implementation by Conny Wals sugested by @vadian
import CoreData
class EditViewModel {
/// **new** instance of item to edit. Don't edit the item, if any, that we pass to VM
var item: Item4
/// Context to use in the isolated changes
let context: NSManagedObjectContext
/// Pass an item if you want to edit one, or nil to generate one
init(item: Item4? = nil){
self.context = PersistenceController.shared.childViewContext()
if let item = item {
self.item = PersistenceController.shared.copyForEditing(of: item, in: context)
} else {
self.item = PersistenceController.shared.newTemporaryInstance(in: context)
}
}
func persist(){
PersistenceController.shared.persist(item)
}
}
import SwiftUI
struct EditItemView: View {
@State var viewModel: EditViewModel
@Environment(\.dismiss) private var dismiss
var body: some View {
NavigationView {
VStack{
TextField( "Item Name", text: Binding(get: {viewModel.item.name ?? ""}, set: {viewModel.item.name = $0}))
.textFieldStyle(RoundedBorderTextFieldStyle())
Spacer()
}
.navigationTitle("Edit Item")
.navigationBarItems(leading: Button("Cancel"){
dismiss()
}, trailing: Button("Save"){
viewModel.persist()
dismiss()
})
}
}
}
struct ItemsView04: View {
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item3.name, ascending: true)],
animation: .default)
private var items: FetchedResults<Item4>
@State var editItemViewIsPresent = false
var body: some View {
NavigationView{
List {
ForEach(items){ item in
NavigationLink(item.name ?? ""){
EditItemView(viewModel: EditViewModel(item: item))
}
}
}
.toolbar {
ToolbarItem {
Button {
editItemViewIsPresent = true
}label:{
Text("+")
}
}
}
.fullScreenCover(isPresented: $editItemViewIsPresent){
EditItemView(viewModel: EditViewModel())
}
}
}
}