3

I have some code which makes a 'Marketplace'. There are 2 views in the marketplace, 'Shirts' & 'Trousers'. When the user taps on an item (a shirt or a pair of trousers), it takes them to a detailed view of the item. This is where I am facing an issue.

Here is the code for the marketplace:

    @StateObject var MarketplaceModel = MarketplaceViewModel()
    
    @State private var selectedMarketplaceFilter: MarketplaceFilterViewModel = .shirt
    
    @Namespace var animation : Namespace.ID
    
    @State var selectedShirt : Shirt!
    
    // Shared Data...
    @EnvironmentObject var sharedData: SharedDataModel
    
    @Binding var shirtData : Shirt
    @Binding var showDetailShirt: Bool
    
    @Binding var trouserData : Trouser
    @Binding var showDetailTrouser: Bool
    
    var body: some View {
        
        ScrollView(.vertical, showsIndicators: false) {
        
            VStack(spacing: 10){
                
                
                if !showDetailShirt && !showDetailTrouser {
                
                marketplaceFilterBar
                    
                }
                
                if selectedMarketplaceFilter == .shirt {
                    MarketplaceShirtView()
                }
                
                if selectedMarketplaceFilter == .trouser {
                    MarketplaceTrouserView()
                }
            }
        }

Here is the code for Shirt & Trouser (both the same data structure):

import SwiftUI
import FirebaseFirestoreSwift
import Firebase

struct Shirt: Identifiable, Codable {
    
    @DocumentID var id: String?
    var shirt_name: String
    var shirt_type: String
    var shirt_image: String
    var shirt_details: String
    var shirt_uid : String
 
}

My SharedDataModel:

import SwiftUI

class SharedDataModel: ObservableObject {
      
  // Detail Shirt Data...
    @Published var detailShirt : Shirt?
    @Published var showDetailShirt : Bool = false
    
    // Detail Trouser Data...
    @Published var detailTrouser : Business?
    @Published var showDetailTrouser : Bool = false
 
}

Here is the DetailView (same for Shirt & Trouser):

    @Binding var shirtData : Shirt
    @Binding var showDetailShirt: Bool
    
    @Namespace var animation: Namespace.ID
    
    // Shared Data Model...
    @EnvironmentObject var sharedData: SharedDataModel
    
    @EnvironmentObject var marketplaceData: MarketplaceViewModel
       
    
    var body: some View {
        
        VStack{
            
            VStack{
                
                HStack {
                    
                    Button(action: {

                                            withAnimation(.easeOut){showDetailShirt.toggle()}

                                        }) {
                                            Image(systemName: "arrow.backward.circle.fill")
   
                                        }
                    
                    
                        Text(shirtData.shirt_name)
 
                }
  
                GeometryReader { geo in
                    WebImage(url: URL(string: shirtData.shirt_image))
                        .resizable()
                        .scaledToFit()
                        .frame(width: geo.size.width * 1, height: 300)
                }
            }
            
            ScrollView(.vertical, showsIndicators: false) {
                
                VStack(alignment: .leading, spacing: 15) {
                    
                    Text(shirtData.shirt_name)
                    
                    Text(shirtData.shirt_type)
                    
                    Text(shirtData.shirt_details)

                }
            }
        }
    }

This is my MarketplaceShirtView code

    @StateObject var MarketplaceModel = MarketplaceViewModel()
    
    @State private var selectedMarketplaceFilter: MarketplaceFilterViewModel = .shirt
   
    @Namespace var animation : Namespace.ID
    
    @State var showDetailShirt = false
    @State var selectedShirt : Shirt!
    
    // Shared Data...
    @EnvironmentObject var sharedData: SharedDataModel
    
    var body: some View {
        
        var columns = Array(repeating: GridItem(.flexible()), count: 2)
        
        ZStack{
            
            VStack(spacing: 10){
                                
                HStack {
                    
                    Text("Find Shirts To Buy")
                        .font(.headline)
                }
                
                
                HStack(spacing: 5) {
                
                    HStack(spacing: 12){
                    
                    Image(systemName: "magnifyingglass")
                        .font(.subheadline)
                    
                    TextField("Search", text: $MarketplaceModel.search)
                        
                    }
                    .background(Color.white)
                      
                    Button {
                     
                    } label: {
                        Image(systemName: "slider.horizontal.3")
                            .foregroundColor(.gray)

                    }
            }
   
                if MarketplaceModel.shirts.isEmpty{

                    ProgressView()
                }
                else{
                    
                    ScrollView(.vertical, showsIndicators: false, content: {

                        LazyVGrid(columns: Array(repeating: GridItem(.flexible(),spacing: 10), count: 2),spacing: 20){
                            
                            ForEach(MarketplaceModel.filteredShirt){shirt in
                                
                                // This is a grid view of items (Shirts)
                                
                                    ShirtView(shirtData: shirt)

                                        .onTapGesture {

                                                selectedShirt = shirt
                                                showDetailShirt.toggle()
                            }
                        }
                    })
                }
            }
            //ERROR HERE: 'Cannot convert value of type 'Binding<Shirt?>' to expected argument type 'Binding<Shirt>'
            if selectedShirt != nil && showDetailShirt{
                
                ShirtDetailView(shirtData: $selectedShirt, showDetailShirt: $showDetailShirt,animation: _animation)
            }
       }
8
  • view models in swiftUI, why?? Commented Jul 11, 2022 at 16:19
  • What do you mean? Commented Jul 11, 2022 at 16:21
  • We don't use view models. We have the View struct and property wrappers which do the same job but better. Commented Jul 11, 2022 at 16:27
  • What do you use instead? I've done a few courses and watched lots of tutorials and they all use view models. Commented Jul 11, 2022 at 16:28
  • So you don't use MVVM structure? What are the benefits of this? Commented Jul 11, 2022 at 16:29

1 Answer 1

1

In this case I think it should be enough just to unwrap binding, like

if selectedShirt != nil && showDetailShirt{
    
    ShirtDetailView(shirtData: Binding($selectedShirt)!, showDetailShirt: $showDetailShirt,animation: _animation)
}
Sign up to request clarification or add additional context in comments.

2 Comments

This fixes the errors, is this way safe too?
As soon as you validated selectedShirt != nil, yes it is.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.