Swiftui 如何编辑子类对象列表

Swiftui 如何编辑子类对象列表,swiftui,Swiftui,我有一个从同一个类派生的不同类的项目列表 目标:使用不同的视图编辑任何对象 模型: class Paper: Hashable, Equatable { var name: String var length: Int init() { name = "" length = 0 } init(name: String, length: Int) { self.name = name

我有一个从同一个类派生的不同类的项目列表

目标:使用不同的视图编辑任何对象

模型:

class Paper: Hashable, Equatable {
    var name: String
    var length: Int

    init() {
        name = ""
        length = 0
    }

    init(name: String, length: Int) {
        self.name = name
        self.length = length
    }

    static func == (lhs: Paper, rhs: Paper) -> Bool {
        return lhs.length == rhs.length
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(length)
    }
}

class ScientificPaper: Paper {
    var biology: Bool

    override init(name: String, length: Int) {
        biology = false
        super.init(name: name, length: length)
    }
}

class TechnicalPaper: Paper {
    var electronics: Bool

    override init(name: String, length: Int) {
        electronics = false
        super.init(name: name, length: length)
    }
}
包含列表的主视图


struct TestView: View {
    @Binding var papers: [Paper]
    @State private var edit = false
    @State private var selectedPaper = Paper()

    var body: some View {

        let scientificBinding = Binding<ScientificPaper>(
            get: {selectedPaper as! ScientificPaper},
            set: { selectedPaper = $0 }
        )

        VStack {
            List {
                ForEach(papers, id: \.self) { paper in
                    HStack {
                        Text(paper.name)
                        Text("\(paper.length)")
                        Spacer()
                        Button("Edit") {
                            selectedPaper = paper
                            edit = true
                        }
                    }
                }
            }
        }
        .sheet(isPresented: $edit) {
            VStack {
                if selectedPaper is ScientificPaper {
                    ScientificForm(paper: scientificBinding)
                }
                if selectedPaper is TechnicalPaper {
                    TechnicalForm(paper: technicalBinding)
                }
            }
        }
    }
}

问题是,在运行时,我得到以下结果:

无法将“Paper”类型的值强制转换为“ScientificPaper”

可能是因为所选纸张已初始化为纸张


编辑属于不同类别的列表项的正确策略是什么?

该错误是由于在
正文中创建了绑定,该绑定在每次刷新时计算,因此绑定无效

解决方案是将绑定作为可计算属性,因此只有在正确的流中进行验证后才请求它

使用Xcode 12.1/iOS 14.1进行测试(演示用于
scientificBinding
仅为简单起见)

struct TestView:View{
@装订文件:[文件]
@国家私有变量编辑=false
@国家私有变量selectedPaper=Paper()

var scientificBinding:Binding{//谢谢Asperi。'错误是由于在body'中创建绑定造成的,这就是问题所在。另一个选项是在调用表单之前创建绑定:let sb=Binding(get:{selectedPaper as!ScientificPaper},set:{selectedPaper=$0})科学形式(论文编号:sb)

struct ScientificForm: View {
    @Binding var paper: ScientificPaper

    var body: some View {
        Form {
            Text("Scientific")
            TextField("Name: ", text: $paper.name)
            TextField("Length: ", value: $paper.length, formatter: NumberFormatter())
            TextField("Biology: ", value: $paper.biology, formatter: NumberFormatter())
        }
    }
}


struct TechnicalForm: View {
    @Binding var paper: TechnicalPaper

    var body: some View {
        Form {
            Text("Technical")
            TextField("Name: ", text: $paper.name)
            TextField("Length: ", value: $paper.length, formatter: NumberFormatter())
            TextField("Electronics: ", value: $paper.electronics, formatter: NumberFormatter())
        }
    }
}

struct TestView: View {
    @Binding var papers: [Paper]
    @State private var edit = false
    @State private var selectedPaper = Paper()
    
    var scientificBinding: Binding<ScientificPaper> {   // << here !!
        return Binding<ScientificPaper>(
            get: {selectedPaper as! ScientificPaper},
            set: { selectedPaper = $0 }
        )
    }

    var body: some View {
        VStack {
            List {
                ForEach(papers, id: \.self) { paper in
                    HStack {
                        Text(paper.name)
                        Text("\(paper.length)")
                        Spacer()
                        Button("Edit") {
                            selectedPaper = paper
                            edit = true
                        }
                    }
                }
            }
        }
        .sheet(isPresented: $edit) {
            VStack {
                if selectedPaper is ScientificPaper {
                    ScientificForm(paper: scientificBinding)
                }
//                if selectedPaper is TechnicalPaper {
//                    TechnicalForm(paper: technicalBinding)
//                }
            }
        }
    }
}