I have a Core Data entity with a few properties, the ones of interest here are a UUID column named "id" and an Int16 column containing values between 0 and 3.
I have a Table in SwiftUI which is correctly arranging the items stored by Core Data into its rows. The "selection:" binds a Set of the "id" values.
I have another view to which I have sent the Set of "id" values (Set<Bin.ID>) (Bin is the name of my entity) using @Binding var ... - so far so good.
Within that view, I can determine that I am correctly getting the set of interest, and most of what I am trying to accomplish I can get to work.
What is driving me up the wall, however, is that I am trying to get a Picker in the child view to let me change the value of the Int16 property (called playMode) of the first selected object from the table.
I have tried numerous things to create that binding but I can't seem to find the magic combination that works in any sensible way.
Here is what I am currently doing, which seems to come closest.
I set up a @State variable within the child view that has the same type as the property of the entity and created an initializer that calls a function to find the first selected item and set that state variable, plus a function to update the entity when the state changes:
@Binding var whichBins: Set<Bin.ID>
@State var playMode: Int16 = 0
init(whichBins: Binding<Set<Bin.ID>>)
{
self._whichBins = whichBins
playMode = getPlayMode(whichBins.wrappedValue)
}
private func getPlayMode(_ val: Set<Bin.ID>) -> Int16
{
if val.count > 0
{
do
{
let fr = try PersistenceController.shared.container.viewContext.fetch(Bin.fetchRequest(forID: val.first!))
for bin in fr
{
if (bin.typ == 1)
{
print("getPlayMode: actual return \(bin.playMode)")
return bin.playMode
}
}
} catch {
let nsError = error as NSError
print("getPlayMode fetch error \(nsError), \(nsError.userInfo)")
}
}
print("getPlayMode: default return existing \(playMode)")
return playMode
}
private func setPlayMode(value:Int16)
{
print("setPlayMode: value=\(value)")
if whichBins.count > 0
{
do
{
let fr = try PersistenceController.shared.container.viewContext.fetch(Bin.fetchRequest(forID: whichBins.first!))
for bin in fr
{
print("setPlayMode: GO GO GO")
bin.playMode = value
try? PersistenceController.shared.container.viewContext.save()
}
} catch {
let nsError = error as NSError
print("setPlayMode fetch error \(nsError), \(nsError.userInfo)")
}
}
}
Within the body of the view, I set up the picker with onChange handlers to update the state variable when the table selection changes and to call the function to set the value in the entity when the picker makes a change:
Picker("Play Mode:", selection: $playMode)
{
Text("Single").tag(Int16(0))
Text("Repeat One").tag(Int16(1))
Divider()
Text("Through End").tag(Int16(2))
Text("Repeat All").tag(Int16(3))
}
.onChange(of: playMode)
{ val in
setPlayMode(value: val)
}
.onChange(of: whichBins)
{ val in
playMode = getPlayMode(val)
}
What is happening is that when I switch the selection in the Table, I can see (from the logging output being produced by "print") that the getPlayMode function is returning the intended value - the one stored in the object - and that when I change the value in the Picker, the setPlayMode function is being called with the intended value (which then gets returned by getPlayMode).
However, when I change the table selection, while getPlayMode is returning the value that it should (as evidenced by "actual return"), the Picker is consistently showing the first item in the list - it never comes up with the intended selected item.
What am I missing?