SwiftUI:随机出现“调用中存在额外参数”错误

99

所以我正在尝试学习SwiftUI和Combine。我通常通过制作一个简单的小费计算器来开始学习新技术。

在编码过程中,我似乎遇到了随机出现的“调用中存在额外的参数”错误。 这是我的SwiftUI文件

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())
    }
}
然而,如果我在TipView主体上添加另一个视图(任何视图),我似乎会得到一个“调用中的额外参数”错误。这里是错误图片。有人知道发生了什么吗?

3
尝试在您的视图周围创建一个 Group { }。在SwiftUI中只允许使用10个视图...使用组可以添加更多视图。或者使用子视图...(这也会使代码更清晰) - Chris
这个可行,我不知道有限制。但是我应该把一些东西分离到它们自己的视图中,而不是使用 Group(Group 完美地工作)。谢谢。请将其写为答案,我会将其设为官方答案。 - Kwoner
Chris和SparkleBeard都是正确的解决方案。 - Kwoner
3个回答

266

尝试在您的视图周围制作一个 Group { }。 在SwiftUI中只允许最多10个视图...使用组,您可以添加更多视图。或者使用子视图...(这将使代码更清晰)


21
在SwiftUI中只允许使用10个。这真的很有帮助。谢谢! - Fred
6
先生,您是正确的。感谢您挽救了我一整天的时间来解决这个错误。 - Mihir
12
感谢苹果又给我加上一个随机限制...现在我的11个视图的代码为了“让代码简单易读”而多了22行包装代码!-感谢你澄清这一点。当我注意到这个错误出现在第11个视图时,我立刻就怀疑又是另一个随机限制... - Azurlake

27

SwiftUI中的@ViewBuilder系统在任何给定的视图容器内限制为10个视图。没有第11个视图的参数,因此您会收到该错误。

基本解决方案:

问题在于您的VStack已经达到了最大容量,但是您可以将这些现有的视图包装在其他容器内。以下是一个非常基本的示例,它允许您显示10个BottomReceiptRow视图:

    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)
    }
}

或者:

您可能更喜欢完全将这些部分重构为它们自己的 View,因为组合使代码更易于阅读。虽然在这里并不是绝对必要的。

如果您确实想这样做,可以考虑一个例子,其中这些收据行都在它们自己的视图中,例如:

    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

这个在Xcode 13.4和swift 5.6.1中仍然是有效的。 - spnkr

2

在SwiftUI中,您可以将最多10个视图堆叠在同一个Stack(VStack、HStack、ZStack)中,因此您可以将一些视图嵌入另一个Stack或Group {}中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接