1

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?

Michel
  • 10,303
  • 17
  • 82
  • 179

1 Answers1

1

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
}
Raja Kishan
  • 16,767
  • 2
  • 26
  • 52
  • Thanks, I tried to follow your idea. After fixing a few details, I think your hint puts me on the right path. But it does not completely work yet. I made another (updated) post here: https://stackoverflow.com/questions/67314204/cannot-update-row-color-while-playing-audio-in-swiftui. – Michel Apr 29 '21 at 09:05
  • After spending some time on the idea of making the environment object bindable. I made a new project just for testing that idea, but as far as I can see it does not work. – Michel Apr 30 '21 at 12:58