ios 为什么我不能跨视图访问id?

a14dhokn  于 2023-05-02  发布在  iOS
关注(0)|答案(3)|浏览(211)

在我的项目中,用户可以有两个最喜欢的产品。他们可以通过点击其中一个(ProductView)来更改它们。点击一个后,将显示一个名为“ProductSheet”的视图。我尝试从上一个视图中携带id,但它不在那里。我需要将id传递到'ProductSheet'和'ProductRowView'中,以便执行更改最喜欢的产品的功能。
我不明白为什么product_id在'ProductSheet'和'ProductRowView'视图中没有值。下面是代码的简化版本:

struct FavouriteProducts: View {
    
    @StateObject var favouriteProductsModel = FavouriteProductsViewModel()
    @State private var showingSheet = false
    @State var selectedProduct: String?
    @State var product_id: String?
        
    
    var body: some View {
        
        ZStack {
            let defaults = UserDefaults.standard
            let keyString: String? = defaults.string(forKey: "key") ?? ""
            
            VStack {
                
                HStack {
                    
                    Text("Tap to change favourite product")
                }
                
                HStack(spacing: 25) {
                    
                    ForEach(favouriteProductsModel.favourite_products, id: \.id){ product in
                        
                        VStack {
                                                                                                                
                            Image("ProductImage")
                                .resizable()
                                                    
                            Text(String(product.product_name ?? ""))

                        }
                        .onTapGesture {
                            selectedProduct = product.id
                            self.product_id = product.id ?? ""
                            self.showingSheet = true
//selectedProduct does have a value in this print statement
                            print("Tapped Product ID: \(String(describing: selectedProduct))")
                        }
                        .sheet(item: $selectedProduct) {
                            favouriteProductsModel.fetchFavouriteProducts(key: keyString ?? "")
                        } content: { item in
                            ProductSheet(product_id: selectedProduct ?? "")
                        }
                    }
                }
            }
        }
        .onLoad {
            let defaults = UserDefaults.standard
            let keyString: String? = defaults.string(forKey: "key") ?? ""
            self.favouriteProductsModel.fetchFavouriteProducts(key: keyString ?? "")
        }
    }
}
struct ProductSheet: View {
    
    @StateObject var marketplaceModel = MarketplaceViewModel()
    @State var product_id: String?

    var body: some View {

        VStack {
            
            // The product_id here is not being displayed, because the variable has no value
            Text(product_id ?? "")
            
            ForEach(marketplaceModel.filteredProduct, id:\.self){ product in
                
                ProductRowView(productData: product, product_id: product_id ?? "")
            }
                        
        }
    }
}
struct ProductRowView: View {
    
    @Environment(\.dismiss) var dismiss
    @StateObject var favouriteProductsModel = FavouriteProductsViewModel()
    @State private var isShowingDetailView = false
    @State var selectedProduct : ProductTile?
    @State var new_id = ""
    var productData: ProductRow
    var product_id: String
    
    var body: some View {
        
        VStack {
            
            HStack {
                Text(productData.title)
                
                HStack {
                    NavigationLink("", isActive: $isShowingDetailView) {
                        ProductSeeAllView(productData: productData, product_id: productData.id)
                    }.navigationTitle("")
                    
                    Button("See All") {
                        isShowingDetailView = true
                    }
                    Image(systemName: "chevron.right")
                }
            }
            
            HStack {
                ScrollView {
                    HStack {
                        ForEach(productData.products ?? []) { product in
                            ProductView(productData: product)
                                .onTapGesture {
                                    new_id = product.id ?? ""
                                    selectedProduct = product
                                    print("Product id: \(selectedProduct?.id ?? "")")
                                    let defaults = UserDefaults.standard
                                    let keyString: String? = defaults.string(forKey: "key") ?? ""
                                    
                                    favouriteProductsModel.changeFavouriteProducts(key: keyString ?? "", current_id: product_id, new_id: new_id ) { (success) in
                                        if success {
                                            dismiss()
                                        } else {
                                            print("Unsuccessful...")
                                        }
                                    }
                                }
                        }
                    }
                }
            }
        }
    }
}

当初始化'ProductSheet'和'ProductRowView'时,我应该传递product_id,但它不起作用。为什么会这样?
编辑:通过进一步的测试,如果第二次初始化工作表,似乎会通过id。它似乎从来没有工作第一次。

ds97pgxw

ds97pgxw1#

我简化了您的代码以向您展示一个可行的解决方案。
工作表是在视图初始化时创建的,因此ProductSheet初始化为nil乘积。您必须添加@Binding以获得所需的行为。

struct Product: Identifiable {
    var id: Int
    var name: String
}

let products = [
    Product(id: 1, name: "Product 1"),
    Product(id: 2, name: "Product 2")
]

struct FavouriteProducts: View {
    @State private var showingSheet = false
    @State private var selectedProduct: Product?

    var body: some View {
        VStack {
            Text("Tap to change favourite product")

            ForEach(products){ product in
                Text(product.name)
                    .onTapGesture {
                        selectedProduct = product
                        showingSheet = true
                    }
            }
        }
        .sheet(isPresented: $showingSheet) {
            ProductSheet(product: $selectedProduct)
        }
    }
}

struct ProductSheet: View {
    @Binding var product: Product?

    var body: some View {
        Text(product?.name ?? "?")
    }
}
fcwjkofz

fcwjkofz2#

应该是let而不是@State var。对于letbody将被自动调用,然后传入的值从上次这个View结构体初始化时起发生了变化,例如。g的。

struct ProductSheet: View {

    // Bad code! don't misuse StateObject for view model objects just use the View structs.
    //@StateObject var marketplaceModel = MarketplaceViewModel()

    let productID: String

仅供参考,我们不需要SwiftUI中的视图模型对象,因为这是View结构的工作。@StateObject用于当您需要在@State中存储引用类型时,例如。例如,当执行异步操作时。如果你使用@StateObject来实现视图模型,你会遇到SwiftUI为视图数据设计的不可变View结构体所要消除的那种一致性错误。

yc0p9oo0

yc0p9oo03#

问题是,数据在第一次初始化时没有传递到工作表。下面的代码阻止了这个bug:

@State private var showingSheet = false
.sheet(isPresented: Binding(
                                        get: { showingSheet },
                                        set: { showingSheet = $0 }
                                    )) {
                                        ProductSheet(product_id: selectedProduct ?? "")
                                    }

相关问题