2

I am pulling my hair out trying to figure out how to get my picker to show the already stored CoreData value. I want it to show on the right side of the picker as if the user just selected it. I have tried adding self.updatedItemAttribute = self.editItem.attribute ?? "" prior to the picker to set the initial value but that does not build. I also tried defining it in @State (e.g. @State var updatedItemAttribute: String = self.editItem.attribute) but that does not build either. If I add a TextField prior to the picker it will set the value, but I do not want to have a TextField with the value just to get it to set. Any ideas on how I get updatedItemAttribute set to editItem.attribute just prior to the picker? Thanks.

import CoreData import SwiftUI struct EditItemView: View { @Environment(\.managedObjectContext) var moc @Environment(\.presentationMode) var presentationMode @ObservedObject var editItem: Item @State var updatedItemName: String = "" @State var updatedItemAttribute: String = "" let attributes = ["Red", "Purple", "Yellow", "Gold"] var body: some View { NavigationView { Form { Section { TextField("Name of item", text: $updatedItemName) .onAppear { self.updatedItemName = self.editItem.name ?? "" } Picker("Test attribute", selection: self.$updatedItemAttribute) { ForEach(attributes, id: \.self) { Text($0) .onAppear { self.updatedItemAttribute = self.editItem.attribute ?? "" } } } } ... 

1 Answer 1

6

You have to this in init as shown below

struct EditItemView: View { @Environment(\.managedObjectContext) var moc @Environment(\.presentationMode) var presentationMode @ObservedObject var editItem: Item @State private var updatedItemName: String @State private var updatedItemAttribute: String init(editItem item: Item) { // << updated here self.editItem = item self._updatedItemName = State<String>(initialValue: item.name ?? "") self._updatedItemAttribute = State<String>(initialValue: item.attribute ?? "") } let attributes = ["Red", "Purple", "Yellow", "Gold"] var body: some View { NavigationView { Form { Section { TextField("Name of item", text: $updatedItemName) Picker("Test attribute", selection: self.$updatedItemAttribute) { ForEach(attributes, id: \.self) { Text($0) } } } } } } } 
Sign up to request clarification or add additional context in comments.

6 Comments

That worked. Thanks so much. One thing I need to understand is why I had to change my preview return from EditItemView(editItem: item) to EditItemView(item), and my call to this page from the previous page from EditItemView(editItem: self.myItem).environment(\.managedObjectContext, self.moc) to EditItemView(self.myItem).environment(\.managedObjectContext, self.moc). I do not get why using the init eliminates the need to call and return using editItem. Do you happen to know?
@Arkyyn, it is due to signature of init - init(_ item: Item). You can change it to init(editItem: Item), and fix first member assignment, to get your previous syntax.
So, I tried that I am still missing something. I tried ` init(editItem: Item) { self._updatedItemName = State<String>(initialValue: editItem.name ?? "") self._updatedItemAttribute = State<String>(initialValue: editItem.attribute ?? "")}` but I got an error that says "Return from initializer without initializing all stored properties. The above makes more sense to me, but I am obviously missing something. Any ideas? I got the other way to work. Just trying to understand though. Thanks for the help.
Wow. I would have never got that I needed to self.editItem = editItem. I also had to change the item.name and item.attribute to editItem.name and editItem.attribute'. What is the self.editItem = editItem` doing? Seems extraneous but it obviously is not.
@Arkyyn, updated again )), as really introduced naming bug, separated 'argument label' and 'argument' and 'member' explicitly to show 'what is what'.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.