Passing @Binding variable from protocol var to if in SwiftUI

I have a model like this:

protocol PurchasableProduct {     var randomId: String { get } }  class Cart: Identifiable {     var items: [PurchasableProduct]          init(items: [PurchasableProduct]) {         self.items = items     } }  class Product: Identifiable, PurchasableProduct {     var randomId = UUID().uuidString     var notes: String = "" }  class DigitalGood: Identifiable, PurchasableProduct {     var randomId = UUID().uuidString } 

where items conform to protocol PurchasableProduct.

I want to build a View that shows cart like this:

struct CartView: View {     @State var cart: Cart          var body: some View {         List {             ForEach(cart.items.indices) { index in                 CartItemView(item: self.$cart.items[index])             }         }     } } 

where CartItemView is:

struct CartItemView: View {     @Binding var item: PurchasableProduct          var body: some View {         VStack {             if self.item is Product {                 Text("Product")             } else {                 Text("Digital Good")             }         }     } } 

That’s working and give me result as This (screenshot)

But I want to extend this a but more that my items element can be passed as a binding variable lets say as:

struct CartItemView: View {     @Binding var item: PurchasableProduct          var body: some View {         VStack {             if self.item is Product {                 VStack {                     TextField("add notes", text: (self.$item as! Product).notes) // ❌ Cannot convert value of type 'String' to expected argument type 'Binding<String>'                     TextField("add notes", text: (self.$item as! Binding<Product>).notes) // ⚠️ Cast from 'Binding<PurchasableProduct>' to unrelated type 'Binding<Product>' always fails                 }             } else {                 Text("Digital Good")             }         }     } } 

What I’m trying to achieve is:

  1. I have a collection of items that depends on a class should be drawn differently
  2. Items have different editable sync that should be binded into CartView

Not sure if thats syntax issue or my approach issue … how to cast this on body to get the correct view based on type?

Add Comment
1 Answer(s)

You may create a custom binding:

struct CartItemView: View {     @Binding var item: PurchasableProduct      var product: Binding<Product>? {         guard item is Product else { return nil }         return .init(             get: {                 self.$item.wrappedValue as! Product             }, set: {                 self.$item.wrappedValue = $0             }         )     }     var body: some View {         VStack {             if product != nil {                 TextField("add notes", text: product!.notes)             } else {                 Text("Digital Good")             }         }     } } 
Add Comment

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.