swift - 如何使用绑定关联 Swift 枚举数组?
问题描述
我的问题与此类似->如何使用 Bind an Associative Swift enum?
我已将提供的示例修改为数组。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 发行说明中考虑这一点:
Collection 协议上的 identify(by:) 方法已被弃用,取而代之的是专用的 init( :id:selection:rowContent:) 和 init( :id:content:) 初始化程序。(52976883, 52029393)
删除了 Int 对 Identifiable 协议的追溯一致性。更改任何依赖此一致性的代码以将 .self 传递给相关初始化程序的 id 参数。Int 的恒定范围继续被接受:
List(0..<5) { Text("Rooms") }
但是,您不应传递在运行时更改的范围。如果您使用在运行时更改的变量来定义范围,则列表将根据初始范围显示视图并忽略对该范围的任何后续更新。
然后,如果您的数组大小不固定,您可能需要更多代码:
正如我在评论中提到的。您无法使枚举可识别(如果可以,请告诉如何操作!)。所以唯一的选择是id: \.self
在ForEach
. 但要做到这一点,我们需要使Instruction
符合Hashable
.
此外,要获得绑定,我们需要其位置的索引。这里的解决方案(findIndex)可能不是最好的性能,但我不希望您的 Instructions 数组有数千个元素......所以应该没问题。
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)
}
}
}
推荐阅读
- azure - azure函数HttpTrigger如何编辑代码参数名称?
- plot - splot 中沿 x 轴的对称绘图
- excel - 我想使用 vba 获取列中数据的频率
- javascript - 延迟加载性能选择选项的静态列表
- amazon-web-services - Nginx:客户端请求正文缓冲到临时文件
- javascript - 使用 redux 为什么我的应用程序状态 isAuthenticated 在任何类型的重新加载后都不会保持设置为 true?
- prolog - 执行列表转换,Prolog
- python - 如何访问电子表格中的另一个页面?
- javascript - 车把问题
- android - 方法代码太大!android compileSdkVersion 27 更改为 compileSdkVersion 30 后