I'm trying to achieve a two way binding-like functionality.
I have a model with an array of identifiable Item
s, var selectedID
holding a UUID of selected Item
, and var proxy
which has get{}
that looks for an Item inside array by UUID and returns it.
While get{}
works well, I can't figure out how to make proxy
mutable to change values of selected Item
by referring to proxy.
I have tried to implement set{}
but nothing works.
import SwiftUI
var words = ["Aaaa", "Bbbb", "Cccc"]
struct Item: Identifiable {
var id = UUID()
var word: String
}
class Model: ObservableObject {
@Published var items: [Item] = [Item(word: "One"), Item(word: "Two"), Item(word: "Three")]
@Published var selectedID: UUID?
var proxy: Item? {
set {
// how to set one property of Item?, but not the whole Item here?
}
get {
let index = items.firstIndex(where: { $0.id == selectedID })
return index != nil ? items[index!] : nil
}
}
}
struct ContentView: View {
@StateObject var model = Model()
var body: some View {
VStack {
// monitoring
MonitorkVue(model: model)
//selections
HStack {
ForEach(model.items.indices, id:\.hashValue) { i in
SelectionVue(item: $model.items[i], model: model)
}
}
}.padding()
}
}
struct MonitorkVue: View {
@ObservedObject var model: Model
var body: some View {
VStack {
Text(model.proxy?.word ?? "no proxy")
// 3rd: cant make item change by referring to proxy
// in order this to work, proxy's set{} need to be implemented somehow..
Button {
model.proxy?.word = words.randomElement()!
} label: {Text("change Proxy")}
}
}
}
struct SelectionVue: View {
@Binding var item: Item
@ObservedObject var model: Model
var body: some View {
VStack {
Text(item.word).padding()
// 1st: making selection
Button {
model.selectedID = item.id } label: {Text("SET")
}.disabled(item.id != model.selectedID ? false : true)
// 2nd: changing item affects proxy,
// this part works ok
Button {
item.word = words.randomElement()!
}label: {Text("change Item")}
}
}
}
Once you SET selection you can randomize Item and proxy will return new values.
But how to make it works the other way around when changing module.proxy.word = "Hello"
would affect selected Item
?
Does anyone knows how to make this two-way shortct? Thank You
CodePudding user response:
Here is a correction and some fix:
struct Item: Identifiable {
var id = UUID()
var word: String
}
class Model: ObservableObject {
@Published var items: [Item] = [Item(word: "One"), Item(word: "Two"), Item(word: "Three")]
@Published var selectedID: UUID?
var proxy: Item? {
get {
let index: Int? = items.firstIndex(where: { value in (selectedID == value.id) })
if let unwrappedIndex: Int = index { return items[unwrappedIndex] } else { return nil }
}
set(newValue) {
if let unwrappedItem: Item = newValue {
let index: Int? = items.firstIndex(where: { value in (unwrappedItem.id == value.id) })
if let unwrappedIndex: Int = index { items[unwrappedIndex] = unwrappedItem }
}
}
}
}