按钮操作块内的 Foreach 循环抛出“Type() 不能符合视图”
Posted
技术标签:
【中文标题】按钮操作块内的 Foreach 循环抛出“Type() 不能符合视图”【英文标题】:Foreach loop inside button action block throws "Type() cannot conform to view" 【发布时间】:2020-07-31 22:19:34 【问题描述】:我有一组视图,我需要从中获取值以便将它们保存到我的上下文中。当单击按钮时尝试遍历这些时,我得到“类型'()'不能符合'视图';只有结构/枚举/类类型可以符合协议”异常。我对 swift 很陌生,我想知道是否有更简单的方法可以做到这一点。提前谢谢你!
这是完整的视图:
struct DetailedView: View
@Environment(\.managedObjectContext) var moc
var targetMuscle : String = "Chest"
let today = Date()
@State public var exerciseCards : [ExerciseCard] = []
@State public var exercise : String = "Bench Press"
@State public var exercises : Int = 0
@State public var showPassedWorkouts : Bool = false
static let taskDateFormat : DateFormatter =
let formatter = DateFormatter()
formatter.dateStyle = .long
return formatter
()
var body: some View
ZStack
VStack
HStack
VStack
Text(targetMuscle).font(.system(size:40)).fontWeight(.medium)
Text("\(today, formatter: Self.taskDateFormat)")
.font(.system(size:20))
.frame(width: 250, height: 30, alignment: .topLeading)
.navigationBarTitle("")
.navigationBarHidden(true)
.padding(.bottom, -7)
Button(action:
self.showPassedWorkouts.toggle()
)
Text("Passed Workouts")
.multilineTextAlignment(.center)
.offset(x: -75, y: 25)
.sheet(isPresented: $showPassedWorkouts)
PassedWorkoutList()
Button(action:
let workout = Workout(context: self.moc)
workout.muscle = self.targetMuscle
workout.date = formattedDateString(day: self.today)
ForEach(0..<exerciseCards.count, id: \.self)number in
let exercise = Exercise(context: self.moc)
ForEach(0..<self.exerciseCards[number].tableRows.count, id: \.self)innerNum in
let exerciseSet = ExerciseSet(context: self.moc)
exerciseSet.reps = self.exerciseCards[number].tableRows[innerNum].reps
exerciseSet.weight = self.exerciseCards[number].tableRows[innerNum].weight
exerciseSet.set = self.exerciseCards[number].tableRows[innerNum].set
exercise.addToExerciseSet(exerciseSet)
workout.addToExercise(exercise)
try? self.moc.save()
)
Text("Finish")
.offset(x: -20, y: 20)
.padding(.bottom, 35)
.padding(.leading)
ScrollView
ForEach(0..<exerciseCards.count, id: \.self) number in
self.exerciseCards[number]
Button(action:
self.exerciseCards.append(ExerciseCard())
)
Text("Add Exercise")
.frame(minWidth: 325)
.padding()
.foregroundColor(.white)
.background(Color.blue.opacity(0.7))
.cornerRadius(20)
.padding(.top)
.frame(width: 400)
.background(Color.white)
func formattedDateString(format: String? = "MMM d, h:mm", day: Date) -> String
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = format
return dateFormatter.string(from: day)
上面的视图还引用了两个视图,第一个是练习卡视图
struct ExerciseCard: View
@State public var exercise : String = "Bench Press"
@State public var tableRows : [ExerciseTableRow] = []
var body: some View
VStack
TextField("Enter Exercise", text: $exercise).textFieldStyle(RoundedBorderTextFieldStyle())
.frame(width: 300)
.multilineTextAlignment(.center)
HStack
Group
Text("Set")
Text("Weight")
Text("Reps")
.padding(.horizontal, 30)
.offset(x: -20, y: 0)
VStack
ForEach(0..<tableRows.count, id: \.self) number in
self.tableRows[number]
.padding(.bottom, 5)
HStack
Button(action:
if self.tableRows.count > 1
self.tableRows.remove(at: self.tableRows.count-1)
)
Text("Remove Set")
.frame(minWidth: 150)
.padding(.vertical, 5)
.foregroundColor(.white)
.background(Color.red)
.cornerRadius(20)
Button(action:
self.tableRows.append(ExerciseTableRow(set: 2, readOnly: false, setWeight: 2, setReps: 2))
)
Text("Add Set")
.frame(minWidth: 150)
.padding(.vertical, 5)
.foregroundColor(.white)
.background(Color.green)
.cornerRadius(20)
.padding()
.padding(.vertical)
.background(Color.offWhite)
.cornerRadius(20)
.shadow(color: Color.black.opacity(0.2), radius: 10, x:10, y:10)
.shadow(color: Color.white.opacity(0.7), radius: 10, x:-5, y:-5)
第二个是 ExerciseTableRow 视图
struct ExerciseTableRow: View
@State public var weight : String = "0"
@State public var reps : String = "0"
var set : Int16
var readOnly : Bool
var setWeight : Int16
var setReps : Int16
var body: some View
HStack
Text(String(set))
.padding(.trailing, 40)
.padding(.leading, 10)
if readOnly == false
Group
TextField("0", text: $weight)
TextField("0", text: $reps)
.textFieldStyle(RoundedBorderTextFieldStyle())
.frame(width: 50)
.multilineTextAlignment(.center)
.keyboardType(.numberPad)
.padding(.horizontal, 30)
else
Group
Text(String(setWeight))
Text(String(setReps))
.frame(width: 50)
.overlay(
RoundedRectangle(cornerRadius: 5)
.stroke(Color.black, lineWidth: 1)
)
.padding(.bottom, 5)
.padding(.horizontal, 30)
【问题讨论】:
请添加更多上下文。至少发布视图代码而不仅仅是一个按钮。 @pawello2222 抱歉延迟回复,但我更新了上面的代码 【参考方案1】:ForEach
是一个 SwiftUI 动态视图容器,用于循环构建视图。对于操作,您必须使用常规 swift for .. in
表达式,例如
Button(action:
let workout = Workout(context: self.moc)
workout.muscle = self.targetMuscle
workout.date = formattedDateString(day: self.today)
for number in 0..<exerciseCards.count
let exercise = Exercise(context: self.moc)
for innerNum in 0..<self.exerciseCards[number].tableRows.count
let exerciseSet = ExerciseSet(context: self.moc)
exerciseSet.reps = self.exerciseCards[number].tableRows[innerNum].reps
exerciseSet.weight = self.exerciseCards[number].tableRows[innerNum].weight
exerciseSet.set = self.exerciseCards[number].tableRows[innerNum].set
exercise.addToExerciseSet(exerciseSet)
workout.addToExercise(exercise)
try? self.moc.save()
)
Text("Finish")
.offset(x: -20, y: 20)
【讨论】:
非常感谢!如果你不介意,还有一件事。在那个 for 循环中,我使用我的数组来访问不同视图中的变量。这些变量连接到文本字段。当我将它们保存到我的上下文中时,我的文本字段不会更新这些变量。从我分享的所有代码中,你有没有看到任何作为这背后的问题突然出现在你面前的东西?例如,如果我尝试访问“self.exerciseCards[number].tableRows[innerNum].reps”行上的 reps 变量,它总是返回 0。如果这与它有任何关系,该变量就是一个 @State 变量。以上是关于按钮操作块内的 Foreach 循环抛出“Type() 不能符合视图”的主要内容,如果未能解决你的问题,请参考以下文章
剃刀块内的asp.net mvc 4 javascript抛出错误
队列ForEach循环抛出InvalidOperationException
R语言使用Repeat函数多次执行代码块内的语句,实现循环执行任务的功能:repeat没有提供任何检查条件,所以编码者必须给出退出重复循环的条件(一般使用if和break)