Cannot assign through subscript / environment key

518 Views Asked by At

While working on an iOS app using SwiftUI, I am facing the following situation. I have set a custom environment key following what I found in some tutorial on the net. Here is the relevant code inside the SceneDelegate.swift file.

    .....
    private struct RowColorMaster: EnvironmentKey {
        static let defaultValue:[[String:Color]] = [[:]]
    }

    extension EnvironmentValues {
        var rowColorMasterDico:[[String:Color]] {
            get {self[RowColorMaster.self]}
            set {self[RowColorMaster.self] = newValue}
        }
    }
    .....
    var rowColorMasterDico:[[String:Color]]
    // Initialize rowColorMasterDico:
    rowColorMasterDico = ......
    .....
    let contentView = ContentView(.....)
                            .environment(\.managedObjectContext, context)
                            .environment(\.rowColorMasterDico, rowColorMasterDico)
    .....

Then further down the view hierarchy in some file:

    .....
    @Environment(\.rowColorMasterDico) var rowColorMasterDico
    .....

    func handleEvent(_ file: String, flag: Bool) {
        rowColorMasterDico[page.index][file] = flag ? Color.red : Color.white
    }

All seems to go well at first until I run into the execution of the handleEvent function where I get this error message:

    Cannot assign through subscript: 'rowColorMasterDico' is a get-only property

Is there something I can modify in my code (maybe the way my custom environment key is set) to be able to assign through subscript?

1

There are 1 best solutions below

2
On

Make your Environment object bindable. Here is the possible solution

First, make binding

private struct RowColorMaster: EnvironmentKey {
    static var defaultValue: Binding<[[String:Color]]> = .constant([[:]])
}

extension EnvironmentValues {
    var rowColorMasterDico: Binding<[[String:Color]]> {
        get {self[RowColorMaster.self]}
        set {self[RowColorMaster.self] = newValue}
    }
}

Next, make a state var inside your parent view

@State private var rowColorMasterDico:[[String:Color]] = []

var body: some Scene {
    WindowGroup {
        RootView()
            .environment(\.rowColorMasterDico, $rowColorMasterDico)
    }
}

Now, in the child view

@Environment(\.rowColorMasterDico) var rowColorMasterDico

func handleEvent(_ file: String, flag: Bool) {
    rowColorMasterDico.wrappedValue[page.index][file] = flag ? Color.red : Color.white
}