Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling EnvironmentObject in a multiple window/tab setting

Tags:

swift

swiftui

How is the best way to provide a different EnvironmentObject (or a substitution) for a multiple tab/window setting?

Let's say we have following MultipleWindow view:

struct MultipleWindow: View {
    @EnvironmentObject var environmentObject: EnvironmentObjectMultipleWindow
    var body: some View {
        VStack {

            ForEach(environmentObject.selectedPhoneSize.indices) { index in
                Button("Select \(environmentObject.selectedPhoneSize[index].size)") {
                    environmentObject.selectedPhoneSize[environmentObject.selectedSizeIndex()].selected = false
                    environmentObject.selectedPhoneSize[index].selected = true
                
                }
                
            }
            
            ForEach(environmentObject.phones) { phone in
                if phone.size == environmentObject.selectedPhoneSize[environmentObject.selectedSizeIndex()].size {
                    Text("\(phone.model): \(phone.price)")
                }
            }
        }
    }
}

And EnvironmentObject:

class EnvironmentObjectMultipleWindow: ObservableObject {
    @Published var selectedPhoneSize = phoneSizes
    @Published var phones = phoneArray
    
    func selectedSizeIndex() -> Int {
        return
            selectedPhoneSize.firstIndex {
                $0.selected == true
            } ?? 0
    }
    
}

struct PhoneSize: Identifiable {
    var id = UUID()
    var size: String
    var selected: Bool
}

let phoneSizes = [
    PhoneSize(size: "M", selected: true),
    PhoneSize(size: "X", selected: false),
    PhoneSize(size: "L", selected: false),
]

struct Phone: Identifiable {
    var id = UUID()
    var size: String
    var model: String
    var price: Int
}

let phoneArray = [
    Phone(size: "L", model: "New", price: 500),
    Phone(size: "X", model: "Old", price: 400),
    Phone(size: "X", model: "New", price: 600),
    Phone(size: "M", model: "New", price: 650)
]

and AppDelegate:

@main
struct Testing_appApp: App {
    @StateObject var environmentObject = EnvironmentObjectMultipleWindow()

    var body: some Scene {
        WindowGroup {
            MultipleWindow().environmentObject(environmentObject)
        }
    }
}

It works as expected - you first choose a model size and then see filtered results from ForEach. The issue is that when you open additional window (i.e. in iPad or macOS), any selection you make will be made in all the windows. I use EnvironmentObject because I use it throughout the app. The same I use i.e. for tag-selection so I could change the current view from any view without any issue. Is there a way to keep all the benefits of EnvironemntObject and present a different EnvironmentObjectMultipleWindow for each window or tab?

like image 345
cluelessCoder Avatar asked May 06 '26 17:05

cluelessCoder


1 Answers

You need to create object in place

var body: some Scene {
    WindowGroup {
        MultipleWindow()
          .environmentObject(EnvironmentObjectMultipleWindow())  // << here !!
    }
}
like image 55
Asperi Avatar answered May 09 '26 09:05

Asperi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!