SwiftUI点击按钮添加含TextField/单选按钮的行时崩溃如何解决?
核心崩溃原因
- 点击添加按钮时仅向
skillList追加了元素,没有同步给evalList追加对应元素,两个数组长度不一致,后续通过下标访问evalList时直接触发数组越界崩溃 @State属性定义在了ContentView结构体外部,不符合SwiftUI状态属性的使用规范- 删除条目时仅移除了
skillList的对应元素,没有同步移除evalList的同下标元素,也会触发数组越界
修正后代码
1. ContentView.swift
struct ContentView: View { // 状态属性必须放在View结构体内部 @State var skills = [String]() @State var skillsEvals = [String]() var body: some View { NavigationView{ VStack(alignment: .leading, spacing: 8) { HStack{ Text("Skills").font(.headline) Spacer() } HStack{ Text("Add up to 5 skills").font(.callout) Spacer() } SkillListEditor(evalList: $skillsEvals, skillList: $skills) Spacer() } .padding() } } }
2. DynamicSkills.swift
struct SkillListEditor: View { @Binding var evalList: [String] @Binding var skillList: [String] var body: some View { ForEach(0..<skillList.count, id: \.self) { index in // SwiftUI支持直接用$数组[index]获取对应元素的Binding,无需自定义绑定方法 ListItem(skillEvaluation: $evalList[index], text: $skillList[index]) { // 删除时同步操作两个数组,保证长度一致 skillList.remove(at: index) evalList.remove(at: index) } } // 增加最多5条的限制,匹配界面提示 if skillList.count < 5 { AddButton{ // 添加时同步给两个数组追加元素 skillList.append("") evalList.append("1") // 默认赋值1分,也可根据需求放空字符串 } } } } fileprivate struct ListItem: View { @Binding var skillEvaluation: String @Binding var text: String var removeAction: () -> Void var body: some View { VStack(alignment: .leading, spacing: 8){ Spacer().frame(height: 8) HStack{ Button(action: removeAction) { Image(systemName: "minus.circle.fill") .foregroundColor(.red) .padding(.horizontal) } TextField("Skill", text: $text) .padding(.all) .background(Color(red: 239.0/255.0, green: 243.0/255.0, blue: 244.0/255.0, opacity: 1.0)) .cornerRadius(6) } HStack{ Text("Evaluation").font(.callout) Spacer() } HStack{ RadioButtonField(id: "1", label: "1", isMarked: skillEvaluation == "1") { selected in skillEvaluation = selected } Spacer() RadioButtonField(id: "2", label: "2", isMarked: skillEvaluation == "2") { selected in skillEvaluation = selected } Spacer() RadioButtonField(id: "3", label: "3", isMarked: skillEvaluation == "3") { selected in skillEvaluation = selected } Spacer() RadioButtonField(id: "4", label: "4", isMarked: skillEvaluation == "4") { selected in skillEvaluation = selected } Spacer() RadioButtonField(id: "5", label: "5", isMarked: skillEvaluation == "5") { selected in skillEvaluation = selected } } } } } fileprivate struct AddButton: View { var addAction: () -> Void var body: some View { HStack{ Spacer() Button(action: addAction) { Text("add skill") .padding(.horizontal, 12) .padding(.vertical, 6) .background(.white) .foregroundColor(Color("PassioGreen")) .overlay(RoundedRectangle(cornerRadius: 25).stroke(Color("PassioGreen"), lineWidth: 2)) } }.padding(.top, 14) } }
3. 单选按钮代码无需修改,可直接沿用原有实现
可选优化建议
可以把技能和对应的评分封装到同一个结构体中,不需要维护两个独立数组,逻辑更清晰也不会出现长度不一致的问题:
struct SkillItem: Identifiable { let id = UUID() var name: String var evaluation: String }
后续状态可直接定义为@State var skillItems: [SkillItem] = [],增删操作只需要处理这一个数组即可。
内容的提问来源于stack exchange,提问作者Thorvald
相关产品推荐
相关产品推荐

