我的问题与此类似-> 如何使用绑定关联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] }
Run Code Online (Sandbox Code Playgroud)
好的,如果数组的大小固定:
ForEach(0..<viewModel.box.instructions.count) { index -> GroupView in
return GroupView(v: self.viewModel.bindingGroup(idx: index))
}
Run Code Online (Sandbox Code Playgroud)
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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果阵列不是固定的,则应从iOS13发行说明中考虑:
不赞成使用Collection协议上的Identification(by :)方法,而推荐使用专用的init(:id:selection:rowContent :)和init(:id:content :)初始化程序。(52976883,52029393)
Int与可识别协议的追溯一致性已删除。更改所有依赖此一致性的代码,以将.self传递给相关初始化程序的id参数。不断接受Int的恒定范围:
Run Code Online (Sandbox Code Playgroud)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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
146 次 |
| 最近记录: |