[英]How can I make a State wrapper outside of View in SwiftUI?
我知道 State 包装器是为 View 设计的,它们是为这个目标而设计的,但如果可能的话,我想尝试构建和测试一些代码,我的目标只是为了学习目的,
我的代码有两个大问题!
Xcode 无法找到T 。
如何初始化我的 state?
import SwiftUI
var state: State<T> where T: StringProtocol = State(get: { state }, set: { newValue in state = newValue })
struct ContentView: View {
var body: some View {
Text(state)
}
}
更新:我可以在这里为 Binding 做同样的事情,现在我想为 State 以及 up 代码做同样的事情
import SwiftUI
var state2: String = String() { didSet { print(state2) } }
var binding: Binding = Binding.init(get: { state2 }, set: { newValue in state2 = newValue })
struct ContentView: View {
var body: some View {
TextField("Enter your text", text: binding)
}
}
如果我能找到我的问题的答案,我可以定义我的 State 并在视图之外进行绑定,完成了 50% 的工作,State Wrapper 还需要另外 50%。
新更新:
import SwiftUI
var state: State<String> = State.init(initialValue: "Hello") { didSet { print(state.wrappedValue) } }
var binding: Binding = Binding.init(get: { state.wrappedValue }, set: { newValue in state = State(wrappedValue: newValue) })
struct ContentView: View {
var body: some View {
Text(state) // <<: Here is the issue!
TextField("Enter your text", text: binding)
}
}
即使您在视图之外创建了 State 包装器,视图如何知道何时刷新其主体?
如果没有通知视图的方法,您的代码将执行以下操作:
struct ContentView: View {
var body: some View {
Text("Hello")
}
}
接下来你能做什么取决于你想要达到的目标。
如果您只需要一种在视图外复制 State 行为的方法,我建议您仔细查看 Combine 框架。
一个有趣的例子是CurrentValueSubject
:
var state = CurrentValueSubject<String, Never>("state1")
它存储当前值并充当发布者。
如果我们在不观察任何东西的视图中使用它会发生什么?
struct ContentView: View {
var body: some View {
Text(state.value)
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
state.value = "state2"
}
}
}
}
答案是:什么都没有。 视图只绘制一次,即使state
发生变化,也不会重新绘制视图。
您需要一种方法来通知视图有关更改。 从理论上讲,您可以执行以下操作:
var state = CurrentValueSubject<String, Never>("state1")
struct ContentView: View {
@State var internalState = ""
var body: some View {
Text(internalState)
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
state.value = "state2"
}
}
.onReceive(state) {
internalState = $0
}
}
}
但这既不优雅也不干净。 在这些情况下,我们可能应该使用@State
:
struct ContentView: View {
@State var state = "state1"
var body: some View {
Text(state)
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
state = "state2"
}
}
}
}
总而言之,如果您需要刷新视图,只需使用本机 SwiftUI 属性包装器(如@State
)。 如果您需要在视图外声明 state 值,请使用ObservableObject
+ @Published
。
否则,有一个巨大的组合框架可以完全满足您的需求。 我建议你看看这些链接:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.