-3

I only wan't to read, not to change the value of a @State property of my SwiftUI view. In .onAppear the value will be changed but that change is not visible to the outside world. Why?

class MyController : UIHostingController<SwiftUIView> {
    public func getText() -> String? {
        rootView.text
    }
}

struct SwiftUIView: View {
    @State public var text: String?
    
    var body: some View {
        Text(text ?? "Hello World")
            .background(Color.red)
            .onAppear {
                text = "so und so"
            }
    }
}

class ViewController: UIViewController {
    var subs = Set<AnyCancellable>()
    var vc: MyController!
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        vc = MyController(rootView: SwiftUIView())
        vc.view.backgroundColor = UIColor.green
        
        addChild(vc)
        view.addSubview(vc.view)
        vc.view.frame = view.bounds
        
        print("text = \(vc.getText() ?? "nil")")
        
        Timer.publish(every: 1, on: .current, in: .default)
            .autoconnect()
            .receive(on: RunLoop.main)
            .sink { _ in
                print("text = \(self.vc.getText() ?? "nil")")
            }
            .store(in: &subs)
    }
}

I know that @State and @ObservedObject exists. @State is for internal managed, @ObservedObject for external managed states. But I don't want to change the value, I only wan't to read. But why is that not possible and why is the return value nil? That's simply wrong. It's no timing problem.

Dominik
  • 101
  • 12
  • 1
    Because the actual value of the State is in a hidden storage area that isn’t public. This secret storage is what allows the value to survive when the struct is mutated. – lorem ipsum Apr 19 '23 at 16:51
  • 1
    "That's simply wrong." No it isn't. This is by design. `@State` properties must always be declared private, since they are the private storage for the view itself. Mutating or even accessing this from outside the body of the view will actually lead to crashes. If you want to be able to read state of a view, use the appropriate property wrapper. `@State` is for private mutable state of a view that shouldn't even be read from outside the view. – Dávid Pásztor Apr 19 '23 at 16:57

1 Answers1

0

Declare the value in the ViewController and pass it down to the SwiftUIView.

malhal
  • 26,330
  • 7
  • 115
  • 133