使用属性包装器时,您可以同时访问$varName
和_varName
,但我并没有真正的区别。例如,这里
import SwiftUI
struct ContentView: View {
@Binding var varName: String
var body: some View {
TextField("", text: $varName) //here you can also use `_varName`
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(varName: .constant("Hello world!"))
}
}
#endif
您可以同时使用$varName
和_varName
。两种解决方案似乎是等效的。这两个变量均为Binding<String>
。但是,如果我需要这样的东西:
import SwiftUI
struct ContentView: View {
@Binding var varName: String
init(varName: Binding<String>) {
self.$varName = varName //ERROR
}
var body: some View {
TextField("", text: $varName)
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(varName: .constant("Hello world!"))
}
}
#endif
我会得到一个错误:
无法分配给属性:“ $ varName”是不可变的
并且我必须使用_varName
来抑制该错误:
struct ContentView: View {
@Binding var varName: String
init(varName: Binding<String>) {
self._varName = varName //this works fine
}
var body: some View {
TextField("", text: _varName)
}
}
它们仍然都是Binding<String>
,那么为什么以前的解决方案不起作用?根据苹果公司(https://developer.apple.com/videos/play/wwdc2019/415/的说法,编译器会将属性包装器转换为两部分。这个:
@Binding var varName: String
成为:
//Compiler-synthesized code
var $varName = Binding<String> = Binding<String>()
public var varName: String {
get { $varName.wrappedValue }
set { $varName.wrappedValue = newValue }
}
$varName
应该为var
,那么为什么出现上述错误?而且,最重要的是,_varName
是什么?它来自哪里?
答案 0 :(得分:4)
合成的_varName
属性是一个可存储的可设置属性,用于保存(在您的情况下)Binding<String>
的实例。
varName
属性映射到包装程序的wrappedValue
属性。 Binding
declares wrappedValue
像这样:
var wrappedValue: Value { get nonmutating set }
由于wrappedValue
是用nonmutating set
声明的,因此合成的varName
属性始终是可设置的(即使self
不可变)。
如果包装器具有$varName
属性,则将合成的projectedValue
属性映射到包装器的projectedValue
属性。 Binding
declares projectedValue
像这样:
var projectedValue: Binding<Value> { get }
由于projectedValue
仅被声明为get
,而不是get set
,因此您永远不能分配给$varName
。
Binding
不需要 来提供projectedValue
属性,因为您可以使用_varName
来获取Binding<String>
对象。 Binding
声明projectedValue
属性的原因是使$
前缀对Binding
的作用与对State
,ObservedObject
的作用相同,和EnvironmentObject
。