UIViewRepresentable in background of a SwiftUI View clobbers preferences

I am working on a project where we have a UIViewRepresentable View in the background of a SwiftUI View, and the preferences for the foreground view are getting clobbered.

If I put the UIViewRepresentable View in the foreground (overlay), then preferences on the SwiftUI view are honored. If I use a native SwiftUI View in the background then the preferences are honored.

Consider this code:

import SwiftUI

struct ContentView: View {
    var body: some View {
        MyView()
            .background() {
                BackgroundView()
            }
            .onPreferenceChange(MyPreferenceKey.self) { value in
                if let value {
                    print("-- preference changed: \(value)")
                } else {
                    print("-- preference changed to `nil`")
                }
            }
    }
}

struct MyView: View {
    var body: some View {
        Text("Hello")
            .preference(key: MyPreferenceKey.self, value: "Hello World")
    }
}

struct MyPreferenceKey: PreferenceKey {
    static func reduce(value: inout String?, nextValue: () -> String?) {}
}

struct BackgroundView: UIViewRepresentable {
    func makeUIView(context: Context) -> UIButton {
        UIButton()
    }

    func updateUIView(_ uiView: UIButton, context: Context) {
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    class Coordinator {
        init() {}
    }
}

BackgroundView is a UIViewRepresentable View. In this case the printed output is:

-- preference changed to `nil`

However, if you use .overlay instead of .background:

            MyView()
                .overlay {
                    BackgroundView()
                }

Then it prints:

-- preference changed: Hello World

Which is what it should. Is there a way to workaround this?

Have you considered passing in your preference value directly as an initializer parameter to your UIViewRepresentable type? If it needs to change, you can pass a binding. What was the motivation for using a preference value?

UIViewRepresentable in background of a SwiftUI View clobbers preferences
 
 
Q