如何使用绑定关联 Swift 枚举数组?



我的问题与此类似 -> 如何使用绑定关联 Swift 枚举?

我已将提供的示例修改为数组。GroupView接受绑定作为参数,因为我希望 GroupView 修改枚举中的数据。原始问题和这个问题之间的区别在于,在这个问题中,枚举是一个数组而不是单个数组。

如何从枚举中提取绑定,以便GroupView可以正确修改枚举? 这是修改后的代码

import SwiftUI
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
VStack {
ForEach(0..<viewModel.box.instructions.count) { index -> GroupView in
let instruction = self.viewModel.box.instructions[index]
return GroupView(v: ????) // How do i extract the binding here???
}
}
}
}
struct GroupView: View {
@Binding var v: Group
var body: some View {
Button("Hello: (self.v.groupValue)") {
self.v.groupValue += 1
}
}
}
class ViewModel : ObservableObject {
@Published var box: Box!
init() {
box = Box(instructions: [
Instruction.group(Group(groupValue: 10)),
Instruction.group(Group(groupValue: 20))
])
}
}
struct Group { var groupValue: Int }
enum Instruction { case group(Group) }
struct Box { var instructions: [Instruction] }

好的,如果数组的大小是固定的:

ForEach(0..<viewModel.box.instructions.count) { index -> GroupView in
return GroupView(v: self.viewModel.bindingGroup(idx: index))
}
class ViewModel : ObservableObject {
@Published var box: Box!
init() {
box = Box(instructions: [
Instruction.group(Group(groupValue: 10)),
Instruction.group(Group(groupValue: 20))
])
}
func bindingGroup(idx: Int) -> Binding<Group> {
return Binding<Group>(get: { () -> Group in
if case .group(let g) = self.box.instructions[idx] {
return g
} else {
return Group(groupValue: 0)
}
}) {
self.box.instructions[idx] = .group($0)
}
}
}

如果您的阵列不是固定的,您应该从 iOS13 发行说明中考虑这一点:

收集协议上的标识(由:(方法在 中已弃用 支持专用 init(:id:selection:rowContent:( 和 init(:id:content:( 初始值设定项。(52976883、52029393(

追溯 删除了 Int 对可识别协议的一致性。更改任何 依赖于此一致性将 .self 传递给 ID 的代码 相关初始值设定项的参数。Int 的恒定范围继续 被接受:

List(0..<5) {
Text("Rooms")
}

但是,不应传递在运行时更改的范围。如果使用在运行时更改的变量来定义 范围,列表根据初始范围显示视图,并且 忽略对范围的任何后续更新。

然后,如果数组的大小不是固定的,则可能需要更多代码:

正如我在评论中提到的。您无法识别枚举(如果可以,请告诉如何!所以唯一的选择是在ForEach中使用id: .self。但要做到这一点,我们需要使Instruction符合Hashable.

此外,要获取绑定,我们需要其位置的索引。这里的解决方案(findIndex(可能不是性能方面最好的东西,但我不希望您的指令数组有数千个元素......所以这应该没问题。

import SwiftUI
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
VStack {
ForEach(viewModel.box.instructions, id: .self) { (instruction: Instruction) -> GroupView in
let idx = self.viewModel.box.instructions.firstIndex(of: instruction)! // I am assuming it will always return a value
return GroupView(v: self.viewModel.bindingGroup(idx: idx))
}
Button("Add Instruction") {
self.viewModel.objectWillChange.send()
self.viewModel.box.instructions.append(Instruction.group(Group(groupValue: 123)))
}
}
}
}
struct GroupView: View {
@Binding var v: Group
var body: some View {
Button("Hello: (self.v.groupValue)") {
self.v.groupValue += 1
}
}
}
struct Group { var groupValue: Int }
enum Instruction: Hashable {
case group(Group)
static func == (lhs: Instruction, rhs: Instruction) -> Bool {
guard case .group(let gL) = lhs else { return false }
guard case .group(let gR) = rhs else { return false }
return gL.groupValue == gR.groupValue
}
func hash(into hasher: inout Hasher) {
if case .group(let g) = self {
hasher.combine(g.groupValue)
}
}
}
struct Box { var instructions: [Instruction] }
class ViewModel : ObservableObject {
@Published var box: Box!
init() {
box = Box(instructions: [
Instruction.group(Group(groupValue: 10)),
Instruction.group(Group(groupValue: 20))
])
}
func bindingGroup(idx: Int) -> Binding<Group> {
return Binding<Group>(get: { () -> Group in
if case .group(let g) = self.box.instructions[idx] {
return g
} else {
return Group(groupValue: 0)
}
}) {
self.box.instructions[idx] = .group($0)
}
}
}

最新更新