UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

NEWB issue - Problems with Picker not functioning as expected...

Forums > SwiftUI

I am working with a Picker that is getting its values from an array of Categories (it's own @Model, no issue there) and needs to save the selected item to a variable in Product.category in another @Model. My list does not allow me to select an item so I am thinking I may have an issue with the binding but cannot see where the issue is.

Any thoughts/guidance would be much appreciated! And if anyone can suggest how i can edit the Product.name var from this View, that would be much appreciated too :)

My code is as follows:

ProductView.swift

import SwiftData
import SwiftUI

struct ProductView: View {
    @Environment(\.modelContext) private var modelContext
    @Environment(\.dismiss) private var dismiss

    @Query(sort: \Category.name) var categories: [Category]

//    let product: Product

    @Bindable var product: Product

    @State private var formType: ProductFormType?
    @State private var showVendors = false
    @State private var showCategories = false

    var body: some View {
        List {
            Section(header: Text("Product Image")) {
                VStack {
                    // MARK: Ternary to add image if there is not one to display and Edit button if there is one
                    if let image = product.image {
                        Image(uiImage: image)
                            .resizable()
                            .scaledToFit()
                            .cornerRadius(12)
                            .clipped()
                            .padding()
                    } else {

                        Text("Add a photo")
    //                    Image(systemName: "photo")
    //                        .foregroundColor(.secondary)
    //                        .opacity(0.2)
    //                        .font(.system(size: 160))
    //                        .frame(width: 250, height: 250)
                    }

                    Button("Edit Photo") {
                        formType = .update(product)
                    }

                }
            }
            Section(header: Text("Where I can buy this Product")) {

                Button("Add or Create Vendor(s)", systemImage: "house.fill") {
                    showVendors.toggle()
                }
                // MARK: Need to find a way to color only SF Symbol
                //            .foregroundColor(.gray)
                .sheet(isPresented: $showVendors) {
                    VendorsView(product: product)
                }

                if let vendors = product.vendors {
                    ViewThatFits {
                        VendorsGridView(vendors: vendors)
                        ScrollView(.horizontal, showsIndicators: false) {
                            VendorsGridView(vendors: vendors)
                        }
                    }
                }

            }

            Section(header: Text("Product Category")) {

                Button("Add or Create Category(ies)", systemImage: "house.fill") {
                    showCategories.toggle()
                }
                // MARK: Need to color only SF Symbol
                //            .foregroundColor(.gray)
                .sheet(isPresented: $showCategories) {
                    CategoriesView(product: product)
                }

                Picker("Please select a Category", selection: $product.category) {
                    ForEach(categories) { category in
                        Text(category.name).tag(category as Category)
//                        Text(category.name)
                    }
                }
                .pickerStyle(.wheel)

                if let categories = product.categories {
                    ViewThatFits {
                        CategoriesGridView(categories: categories)
                        ScrollView(.horizontal, showsIndicators: false) {
                            CategoriesGridView(categories: categories)
                        }
                    }
                }

//                Text("You selected: \(product.category ?? ""))

            }

            Spacer()

            HStack {
                // MARK: Need to add deletion confirmation dialogue
                Button("Delete Product", role: .destructive) {
                    modelContext.delete(product)
                    try? modelContext.save()
                    dismiss()
                }
            }
            .buttonStyle(.borderedProminent)
            .frame(maxWidth: .infinity, alignment: .trailing)

        }
        .sheet(item: $formType) { $0 }
        .navigationTitle(product.name)
        .navigationBarTitleDisplayMode(.inline)
        // MARK: Need to find a way to make Product name editable on this view
        .toolbarRole(.editor)
    }
}

Models

import SwiftData
import UIKit

@Model
class Product {
    var name: String = ""

    @Attribute(.externalStorage)
    var data: Data?

    @Relationship(inverse: \Vendor.products)
    var vendors: [Vendor]?

    var category: String? = ""

    var image: UIImage? {
        if let data {
            return UIImage(data: data)
        } else {
            return nil
        }
    }

    init(name: String, data: Data? = nil, category: String) {
        self.name = name
        self.category = category
        self.data = data
    }
}

@Model
class Category {
    var name: String = ""

    var products: [Product]?

    init(
        name: String
    ) {
        self.name = name
    }   
}

   

Shot in the dark, your picker selection is bound to product.category, which is an optional string. The tag on the picker item is a Category object. I can't see that working as they are incompatible types.

Steve

   

It think this issue might be related to the binding of the Picker in your ProductView. Since you are using @Bindable for the product variable, make sure that the binding is set up correctly for the Picker. Instead of using String for the category property in the Product model, you should use Category as the type, as that's what your Picker is binding to.

   

Hacking with Swift is sponsored by RevenueCat.

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.