Estou tentando passar um valor @Binding para a hierarquia de visualizações do SwiftUI usando uma @EnvironmentKey personalizada. Na minha NestedView, estou usando uma combinação de @Environment e @Binding como esta:
@Environment(\.featureEnabledBinding) @Binding var myBool: Bool
Eu deveria conseguir usar isso em um Toggle como:
Toggle(isOn: $myBool, label: { Text("Toggle") })
Entretanto, isso me dá um erro do compilador:
Não é possível encontrar '$myBool' no escopo
isso funciona perfeitamente:
Toggle(isOn: _myBool.wrappedValue, label: { Text("Toggle") })
Isso é o oposto do que eu esperava. Pelo que entendi: • _myBool deve ser o wrapper (Binding) • $myBool deve ser o valor projetado (também um Binding)
Aqui está meu código
Configuração do ambiente:
struct FeatureEnabledKey: EnvironmentKey {
static let defaultValue: Binding<Bool> = .constant(false)
}
extension EnvironmentValues {
var featureEnabledBinding: Binding<Bool> {
get { self[FeatureEnabledKey.self] }
set { self[FeatureEnabledKey.self] = newValue }
}
}
e Exemplo Mínimo
struct ParentView: View {
@State private var isFeatureEnabled = false
var body: some View {
NestedView()
.environment(\.featureEnabledBinding, $isFeatureEnabled)
}
}
struct NestedView: View {
@Environment(\.featureEnabledBinding) @Binding var myBool: Bool
var body: some View {
VStack {
// ❌ This gives an error : Cannot find '$myBool' in scope
// Toggle(isOn: $myBool, label: { Text("Toggle") })
// ✅ This works fine
Toggle("Working Toggle", isOn: _myBool.wrappedValue)
}
}
}
Pergunta: Por que $myBool está indisponível ou inválido neste contexto? É um bug conhecido do SwiftUI/compilador com wrappers de propriedade dupla (@Environment @Binding)? Ou meu entendimento não está correto.
Xcode: 16.3
Isto é intencional. A partir da proposta de wrappers de propriedade ,
Portanto
$myBool
, teria acessado o valor projetado deEnvironment
(ie_myBool.projectedValue
). Mas, como oEnvironment
wrapper de propriedade não possui umprojectedValue
, a$myBool
propriedade não é gerada.Um caso semelhante é o built-in
editMode
, ou o agora obsoletopresentationMode
. Prefiro não escrevê-loBinding
como um wrapper de propriedade e, em vez disso, escrevê-lo como parte do tipo de propriedade.Então
myBool
seria umBinding<Bool>
,myBool.wrappedValue
seria oBool
.Considere também fazer o que
editMode
faz: alterar o tipo do valor do ambiente paraBinding<Bool>?
e alterar o valor padrão paranil
. Isso torna óbvio se você esqueceu de definir o valor do ambiente.