SwiftUI: Random "Extra argument in call" error

So I'm trying to learn SwiftUI and Combine. I usually start new tech by making a simple tip calculator.

I seem to be getting a random "Extra argument in call." error while coding Here is my SwiftUI File

import SwiftUI


internal enum ReceiptRowType {
case subtotal
case tax
case total
case tip
case grandTotal
}


struct TipView: View {
@ObservedObject internal var adBannerView: BannerAdView = BannerAdView()
@ObservedObject internal var receiptViewModel: ReceiptViewModel


private let percentageFormatter: NumberFormatter = {
let f = NumberFormatter()
f.numberStyle = .percent
return f
}()


var body: some View {
ZStack {
Color.white
.scaledToFit()


VStack {
if adBannerView.adHasLoaded {
adBannerView
.frame(maxHeight: adBannerView.adHeight)
.animation(.easeInOut(duration: 2.0))
}


BorderView()


Text(ARCHLocalizedStrings.receipt)
.foregroundColor(Color.gray)


BorderView()


HStack {
Spacer()


Button(action: {
self.receiptViewModel.addNewReceiptItem()
}) {
Text(ARCHLocalizedStrings.buttonTitleAddItem)
}
}


BorderView()


ScrollView {
ForEach(receiptViewModel.receiptItems) { receiptItem in
ItemView(receiptItem: receiptItem)


if receiptItem != self.receiptViewModel.receiptItems.last {
Divider()
}
}
}


BorderView()


BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.subtotal,
title: ARCHLocalizedStrings.subtotal)


BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.tax,
title: ARCHLocalizedStrings.tax)
}
.padding(.horizontal, ARCHSwiftUILayoutConstants.defaultPaddingAndSpacing)
}
}
}


struct BorderView: View {
var body: some View {
Text("================================")
.lineLimit(1)
.foregroundColor(Color.gray)
.minimumScaleFactor(0.5)
}
}


struct ItemView: View {
@ObservedObject var receiptItem: ReceiptItemViewModel


var body: some View {
HStack {
TextField(receiptItem.name, text: $receiptItem.name)
.textFieldStyle(RoundedBorderTextFieldStyle())
.foregroundColor(Color.gray)
.multilineTextAlignment(TextAlignment.leading)


TextField("Price", value: $receiptItem.price, formatter: ARCHUtilities.currencyFormatter)
.textFieldStyle(RoundedBorderTextFieldStyle())
.foregroundColor(Color.gray)
.multilineTextAlignment(TextAlignment.trailing)
.minimumScaleFactor(0.5)
.frame(width: ARCHSwiftUILayoutConstants.widthForCurrency)
}
}
}


struct BottomOfReceiptRow: View {
@ObservedObject internal var receiptViewModel: ReceiptViewModel


internal var type: ReceiptRowType
internal var title: String


var body: some View {
HStack {
Spacer()


Text(title)
.foregroundColor(Color.gray)


if type == ReceiptRowType.subtotal {
Text("\(receiptViewModel.subtotal)")
.foregroundColor(Color.gray)
.frame(width: ARCHSwiftUILayoutConstants.widthForCurrency)
} else if type == ReceiptRowType.tax {
Text("\(receiptViewModel.taxRate)")
.foregroundColor(Color.gray)
.frame(width: ARCHSwiftUILayoutConstants.widthForCurrency)
} else if type == ReceiptRowType.total {
Text("\(receiptViewModel.total)")
.foregroundColor(Color.gray)
.frame(width: ARCHSwiftUILayoutConstants.widthForCurrency)
} else if type == ReceiptRowType.tip {


} else if type == ReceiptRowType.grandTotal {
Text("\(receiptViewModel.grandTotal)")
.foregroundColor(Color.gray)
.frame(width: ARCHSwiftUILayoutConstants.widthForCurrency)
}
}
}
}


struct TipView_Previews: PreviewProvider {
static var previews: some View {
TipView(receiptViewModel: ReceiptViewModel())
}
}

However, if I add another view on the TipView body (Any View) I seem to get a "Extra argument in call" error.

Picture of error here

Does anyone know what's going on?

24351 次浏览

The @ViewBuilder system in SwiftUI is limited to 10 views within any given view container. There's no argument for an 11th view, so you get that error.

Basic solution:

The issue here is that your VStack is at maximum capacity, however you can wrap those existing views inside of other containers. As a very basic example that would allow you to show 10 BottomReceiptRow views:

    var body: some View {
ZStack {
Color.white
.scaledToFit()


// Modifications start here


VStack {
if adBannerView.adHasLoaded {
adBannerView
.frame(maxHeight: adBannerView.adHeight)
.animation(.easeInOut(duration: 2.0))
}


BorderView()


Text(ARCHLocalizedStrings.receipt)
.foregroundColor(Color.gray)


BorderView()


HStack {
Spacer()


Button(action: {
self.receiptViewModel.addNewReceiptItem()
}) {
Text(ARCHLocalizedStrings.buttonTitleAddItem)
}
}


BorderView()


ScrollView {
ForEach(receiptViewModel.receiptItems) { receiptItem in
ItemView(receiptItem: receiptItem)


if receiptItem != self.receiptViewModel.receiptItems.last {
Divider()
}
}
}


BorderView()


Group {
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.subtotal,
title: ARCHLocalizedStrings.subtotal)


BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.tax,
title: ARCHLocalizedStrings.tax)


BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue,
title: ARCHLocalizedStrings.someValue)


BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue2,
title: ARCHLocalizedStrings.someValue2)


BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue3,
title: ARCHLocalizedStrings.someValue3)


BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue4,
title: ARCHLocalizedStrings.someValue4)


BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue5,
title: ARCHLocalizedStrings.someValue5)
}
// Modifications end here


}
.padding(.horizontal, ARCHSwiftUILayoutConstants.defaultPaddingAndSpacing)
}
}

Alternatively:

You may prefer to completely refactor these sections into their own View as composition makes the code easier to read. It's not strictly necessary here though.

If you did want to do that, you could consider an example where those receipt rows are all in their own view like:

    var body: some View {
ZStack {
Color.white
.scaledToFit()


VStack {
if adBannerView.adHasLoaded {
adBannerView
.frame(maxHeight: adBannerView.adHeight)
.animation(.easeInOut(duration: 2.0))
}


BorderView()


Text(ARCHLocalizedStrings.receipt)
.foregroundColor(Color.gray)


BorderView()


HStack {
Spacer()


Button(action: {
self.receiptViewModel.addNewReceiptItem()
}) {
Text(ARCHLocalizedStrings.buttonTitleAddItem)
}
}


BorderView()


ScrollView {
ForEach(receiptViewModel.receiptItems) { receiptItem in
ItemView(receiptItem: receiptItem)


if receiptItem != self.receiptViewModel.receiptItems.last {
Divider()
}
}
}


BorderView()


bottomRow
}
.padding(.horizontal, ARCHSwiftUILayoutConstants.defaultPaddingAndSpacing)
}
}


// Additional computed property in TipView
var bottomRow: some View {
Group {
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.subtotal,
title: ARCHLocalizedStrings.subtotal)


BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.tax,
title: ARCHLocalizedStrings.tax)


BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue,
title: ARCHLocalizedStrings.someValue)


BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue2,
title: ARCHLocalizedStrings.someValue2)


BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue3,
title: ARCHLocalizedStrings.someValue3)


BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue4,
title: ARCHLocalizedStrings.someValue4)


BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue5,
title: ARCHLocalizedStrings.someValue5)
}
} // end bottomRow

try making a Group { } around your views. just 10 are allowed in Swiftui...with group you can add more. or use subviews...(would be cleaner code too)

In SwiftUI you can stack up to 10 views in the same Stack (VStack, HStack, ZStack), so you can Embed some Views inside another Stack or inside Group {}.