web-dev-qa-db-fra.com

SwiftUI: erreur aléatoire "Argument supplémentaire lors de l'appel"

J'essaye donc d'apprendre SwiftUI et Combine. Je commence généralement une nouvelle technologie en créant un simple calculateur de pourboire.

Il semble que je reçois un "argument supplémentaire lors de l'appel" au hasard. erreur lors du codage Voici mon fichier 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())
    }
}

Cependant, si j'ajoute une autre vue sur le corps de TipView (toute vue), il me semble obtenir une erreur "Argument supplémentaire dans l'appel".

Image d'erreur ici

Quelqu'un sait-il ce qui se passe?

7
user2593831

Le système @ViewBuilder dans SwiftUI est limité à 10 vues dans un conteneur de vues donné. Il n'y a aucun argument pour une 11e vue, donc vous obtenez cette erreur.

Solution basique:

Le problème ici est que votre VStack est à sa capacité maximale, mais vous pouvez envelopper ces vues existantes à l'intérieur d'autres conteneurs. Comme exemple très basique qui vous permettrait d'afficher 10 vues 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)
    }
}

Alternativement:

Vous préférerez peut-être refactoriser complètement ces sections dans leur propre View car la composition rend le code plus facile à lire. Ce n'est cependant pas strictement nécessaire ici.

Si vous voulez faire cela, vous pouvez envisager un exemple où ces lignes de reçu sont toutes dans leur propre vue, comme:

    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
3
Sparklebeard