繁体   English   中英

如何在 SwiftUI 的视图之外制作 State 包装器?

[英]How can I make a State wrapper outside of View in SwiftUI?

我知道 State 包装器是为 View 设计的,它们是为这个目标而设计的,但如果可能的话,我想尝试构建和测试一些代码,我的目标只是为了学习目的,

我的代码有两个大问题!

  1. Xcode 无法找到T

  2. 如何初始化我的 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM