lorenzofiamingo / swiftui-variadic-views

VariadicViews extends SwiftUI's capabilities by introducing a versatile way to extrapolate child views dynamically from opaque view content.
MIT License
0 stars 0 forks source link

Custom environment values not honored #1

Open cyrillelegrand opened 2 weeks ago

cyrillelegrand commented 2 weeks ago

Hi! I need to pass down custom environment values to my variadic children. I've noticed that this is impossible, see a minimal reproduction below:

import SwiftUI
import VariadicViews

struct TestKey: EnvironmentKey {
    static var defaultValue: Int = 0
}

extension EnvironmentValues {
    var testValue: Int {
        get { self[TestKey.self] }
        set { self[TestKey.self] = newValue }
    }
}

struct VariadicThing<Content: View>: View {
    @ViewBuilder let content: Content

    var body: some View {
        MultiVariadicView(content) { children in
            ForEach(children) { child in
                child
                    .environment(\.testValue, 42) // my custom environment value is not honored
                    .environment(\.colorScheme, .dark) // but any system-provided env. value is honored!
            }
        }
    }
}

struct Tester: View {
    let name: String
    @Environment(\.testValue) var testValue

    var body: some View {
        Text("\(name) = \(testValue)").background(Color(uiColor: .systemBackground))
    }
}

#Preview {
    VStack {
        VariadicThing {
            Tester(name: "Test 1")
            Tester(name: "Test 2")
        }
        Text("All should be = 42").foregroundStyle(.secondary)
    }
    .environment(\.colorScheme, .light)
}

Here is the result:

Screenshot 2024-06-26 at 00 32 42

It should read Test1 = 42 and Test2 = 42. The system-provided environment (\.colorScheme) is correctly passed down to each child, but not my custom environment value.

It works if I do

MultiVariadicView(content.environment(\.testValue, 42)) { children in ... }

but that's not what I want: in my actual project, the values can differ for each child, so I need it inside the ForEach.

Is this a limitation from using a private-ish API like _VariadicView ?

I know this library might very well not be maintained for much longer because iOS 18 offers this natively, but my project targets iOS 16.

cyrillelegrand commented 1 week ago

After further research, the problem also arises with the new Group(subviewsOf:transform:) in iOS 18 (which coincidentally has the same API than this package).

This indeed seems like a bug in SwiftUI. I've filed a radar under #FB14070467 which you can feel free to duplicate.

Here's the attached demo project I sent to Apple. It both exhibits the problem with the new iOS 18 API, and with this package. As-is, it needs Xcode 16 to compile, but it also runs on Xcode 15 and iOS 16 when commenting out the few lines related to the new API.

variadic_test.zip