我使用@AppStorage沿着SwiftUI Toggle来管理UserDefaults变量。我的期望是在变量由于Toggle交互而发生变化时执行一些操作,因此我需要在@AppStorage变量的willSet部分执行一些代码。
但是,当我直接将@AppStorage变量绑定到Toggle的isOn状态时,willSet不会触发。相比之下,当我将@State变量绑定到Toggle并在@State变量更改时修改@AppStorage变量时,willSet中的代码确实会被执行。
为什么会这样呢?为什么Toggle对@AppStorage变量的内部修改似乎绕过了我的willSet?有没有更优雅的方式来达到我的要求?
下面是示例代码来说明这个问题:
struct ContentView: View {
@State var stateVariable = false
@AppStorage("userDefaultVariable") var userDefaultVariable: Bool = false {
willSet {
print("userDefaultVariable will set, newValue: \(newValue)")
}
}
var body: some View {
VStack{
Toggle("Directly modify userDefaultVariable",isOn: $userDefaultVariable)
Toggle("Indirectly modify userDefaultVariable",isOn: $stateVariable)
.onChange(of: stateVariable, perform: { value in
userDefaultVariable = value
})
}
}
}
字符串
在此代码中,“直接修改userDefaultVariable”切换不会触发userDefaultVariable的willSet中的print语句。但是,“间接修改userDefaultVariable”切换在修改@State变量stateVariable时会触发print语句,而stateVariable又会修改userDefaultVariable。
1条答案
按热度按时间emeijp431#
像
AppStorage
和State
这样的属性 Package 器被编译成 Package 器类型的存储属性,以及获取和设置存储属性的wrappedValue
的计算属性。还有一个以$
为前缀的computed属性,它获取projectedValue
。字符串
变成:
型
根据this post here,当您添加
willSet
时,它将应用于计算属性userDefaultVariable
,而不是_userDefaultVariable
或$userDefaultVariable
。因此,只要您没有直接使用userDefaultVariable = ...
设置它,就不会触发willSet
。更复杂的是,
Binding.wrappedValue
和AppStorage.wrappedValue
都有一个nonmutating
setter。我认为这里唯一的解决方案是制作自己的
Binding
,并在set:
参数的开头添加任何您想要的代码:型
您可以将其重构到自己的属性 Package 器中:
型
使用方法:
型