调用BarView≥11次出现'Extra argument in call'错误求助
嘿,这个问题我太熟悉了!你碰到的是SwiftUI容器视图(HStack/VStack/ZStack)的一个默认限制——它们的标准ViewBuilder初始化器最多只支持10个子视图。这是因为Swift的泛型函数在处理可变参数时,默认展开的上限就是10个,所以当你放第11个视图时,编译器就会认为你传入了多余的参数,抛出「Extra argument in call」错误;放12个的话,就会报多个位置的参数错误,完全符合你看到的现象。
下面给你两种靠谱的解决方法,还有一个小的代码优化建议:
方法一:用Group包裹多余的子视图
Group是SwiftUI里的特殊视图,它会把内部所有视图合并成一个单一的View实例,以此绕过10个子视图的限制。你可以把前10个BarView放进一个Group,剩下的放在外面:
HStack{ Group { BarView(barGradeValue: 0, barSendValue: 10, barFlashValue: 10) BarView(barGradeValue: 1, barSendValue: 20, barFlashValue: 10) BarView(barGradeValue: 2, barSendValue: 30, barFlashValue: 10) BarView(barGradeValue: 3, barSendValue: 40, barFlashValue: 10) BarView(barGradeValue: 4, barSendValue: 50, barFlashValue: 10) BarView(barGradeValue: 5, barSendValue: 60, barFlashValue: 10) BarView(barGradeValue: 6, barSendValue: 50, barFlashValue: 10) BarView(barGradeValue: 7, barSendValue: 40, barFlashValue: 10) BarView(barGradeValue: 8, barSendValue: 30, barFlashValue: 10) BarView(barGradeValue: 9, barSendValue: 20, barFlashValue: 10) } BarView(barGradeValue: 10, barSendValue: 10, barFlashValue: 10) }
这样HStack里就只有两个子视图(Group和第11个BarView),编译器就不会报错了。
方法二:用ForEach循环生成视图(更推荐)
手动写11个BarView不仅麻烦,后期维护也头疼。用ForEach循环生成视图才是更优雅的方式,你之前尝试循环没成功,可能是没处理好数据和id的问题,我给你写个完整示例:
首先,把你的BarView数据整理成一个数组(可以放在ContentView里):
let barItems: [(grade: Int, send: Int, flash: Int)] = [ (0, 10, 10), (1, 20, 10), (2, 30, 10), (3, 40, 10), (4, 50, 10), (5, 60, 10), (6, 50, 10), (7, 40, 10), (8, 30, 10), (9, 20, 10), (10, 10, 10) ]
然后在HStack里用ForEach遍历这个数组:
HStack { ForEach(barItems, id: \.grade) { item in BarView( barGradeValue: item.grade, barSendValue: CGFloat(item.send), barFlashValue: CGFloat(item.flash) ) } }
这里id: \.grade是因为每个grade都是唯一的,ForEach需要一个可识别的id来追踪视图的变化。如果你的数据可能有重复的grade,可以给每个item加个UUID()作为唯一id,或者让数据结构体遵循Identifiable协议。
额外优化:修正BarView里的ContentView实例问题
看到你的BarView里直接创建了var content = ContentView(),这其实是个不太好的做法——SwiftUI的View是值类型,这样会生成一个全新的ContentView实例,而不是引用当前显示的那个,可能会导致数据不一致。
更好的做法是把需要的gradesV和gradesColor作为参数传给BarView,比如修改BarView:
struct BarView: View { var barGradeValue: Int var barSendValue: CGFloat var barFlashValue: CGFloat var gradeText: String var gradeColor: Color var body: some View { VStack { Text(gradeText) ZStack (alignment: .top){ Capsule().frame(width: 20, height: 100) .foregroundColor(Color.gray) Capsule().frame(width: 20, height: barSendValue+barFlashValue) .foregroundColor(Color.yellow) Capsule().frame(width: 20, height: barSendValue) .foregroundColor(gradeColor) } } } }
然后在ForEach里传入对应的文本和颜色:
// 假设ContentView里有gradesV和gradesColor数组 ForEach(barItems, id: \.grade) { item in BarView( barGradeValue: item.grade, barSendValue: CGFloat(item.send), barFlashValue: CGFloat(item.flash), gradeText: gradesV[item.grade], gradeColor: gradesColor[item.grade] ) }
这样就符合SwiftUI的数据流原则,避免了不必要的实例创建。
内容的提问来源于stack exchange,提问作者Gil

