gpt4 book ai didi

ios - @Published 和 .assign 对值更新没有反应

转载 作者:行者123 更新时间:2023-12-01 21:59:04 24 4
gpt4 key购买 nike

SwiftUI 和在这里结合菜鸟,我在操场上隔离了我遇到的问题。这里是游乐场。

final class ReactiveContainer<T: Equatable> {
@Published var containedValue: T?
}

class AppContainer {
static let shared = AppContainer()

let text = ReactiveContainer<String>()
}

struct TestSwiftUIView: View {

@State private var viewModel = "test"

var body: some View {
Text("\(viewModel)")
}

init(textContainer: ReactiveContainer<String>) {

textContainer.$containedValue.compactMap {
print("compact map \($0)")
return $0
}.assign(to: \.viewModel, on: self)
}
}

AppContainer.shared.text.containedValue = "init"


var testView = TestSwiftUIView(textContainer: AppContainer.shared.text)
print(testView)

print("Executing network request")
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
AppContainer.shared.text.containedValue = "Hello world"
print(testView)
}

当我运行操场时,这就是正在发生的事情:
compact map Optional("init")
TestSwiftUIView(_viewModel: SwiftUI.State<Swift.String>(_value: "test", _location: nil))
Executing network request
TestSwiftUIView(_viewModel: SwiftUI.State<Swift.String>(_value: "test", _location: nil))

如您所见,这里有两个问题:
  • 紧凑 map 闭包仅在订阅时调用一次,但在调度运行时不会调用
  • 赋值运算符永远不会被调用

  • 在过去的几个小时里,我一直在尝试解决这个问题,但没有成功。也许在 SwiftUI/Combine 方面有顶级知识的人可以帮助我,谢谢!

    编辑

    这是工作解决方案:

    struct ContentView: View {

    @State private var viewModel = "test"
    let textContainer: ReactiveContainer<String>

    var body: some View {
    Text(viewModel).onReceive(textContainer.$containedValue) { (newContainedValue) in
    self.viewModel = newContainedValue ?? ""
    }
    }

    init(textContainer: ReactiveContainer<String>) {
    self.textContainer = textContainer
    }
    }

    最佳答案

    我更喜欢使用 ObservableObject/ObservedObject模式,正下方,但其他变体也是可能的(如进一步提供)

    所有测试均使用 Xcode 11.2/iOS 13.2

    final class ReactiveContainer<T: Equatable>: ObservableObject {
    @Published var containedValue: T?
    }

    struct TestSwiftUIView: View {

    @ObservedObject var vm: ReactiveContainer<String>

    var body: some View {
    Text("\(vm.containedValue ?? "<none>")")
    }

    init(textContainer: ReactiveContainer<String>) {
    self._vm = ObservedObject(initialValue: textContainer)
    }
    }

    替代品:

    以下解决了您的情况(如果您不存储订阅者,则发布者将立即取消)
    private var subscriber: AnyCancellable?
    init(textContainer: ReactiveContainer<String>) {

    subscriber = textContainer.$containedValue.compactMap {
    print("compact map \($0)")
    return $0
    }.assign(to: \.viewModel, on: self)
    }

    请注意, View 的状态仅在 View 层次结构中链接,在 Playground 中,就像您所做的那样,它仅包含初始值。

    另一种更适合 SwiftUI 层次结构的可能方法是
    struct TestSwiftUIView: View {

    @State private var viewModel: String = "test"

    var body: some View {
    Text("\(viewModel)")
    .onReceive(publisher) { value in
    self.viewModel = value
    }
    }

    let publisher: AnyPublisher<String, Never>
    init(textContainer: ReactiveContainer<String>) {

    publisher = textContainer.$containedValue.compactMap {
    print("compact map \($0)")
    return $0
    }.eraseToAnyPublisher()
    }
    }

    关于ios - @Published 和 .assign 对值更新没有反应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60667976/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com