How to update a SwiftUI view state from outside (UIViewController for example)

Viewed 9988

I have a SwiftUI view:

struct CatView : View {

    @State var eyesOpened: Bool = false

    var body: some View {
       Image(uiImage: eyesOpened ? #imageLiteral(resourceName: "OpenedEyesCat") : #imageLiteral(resourceName: "ClosedEyesCat"))
    }
}

I'm trying to integrate it with in a regular UIViewController.

let hostingVC = UIHostingController<CatView>(rootView: cat)
addChild(hostingVC)
view.addSubview(hostingVC.view)
hostingVC.view.pinToBounds(of: view)

Now in the UIViewController if I try to set the eyesOpened property I get a

Thread 1: Fatal error: Accessing State<Bool> outside View.body

How are we supposed to make this work? Are SwiftUI views not supposed to work in this scenario?

2 Answers

@State is the wrong thing to use here. You'll need to use @ObservedObject.

@State: Used for when changes occur locally to your SwiftUI view - ie you change eyesOpened from a toggle or a button etc from within the SwiftUI view it self.

@ObservedObject: Binds your SwiftUI view to an external data source - ie an incoming notification or a change in your database, something external to your SwiftUI view.

I would highly recommend you watch the following WWDC video - Data Flow Through SwiftUI

There is something called the notification center that you could use. In short, it is a way that views can communicate between each other without actually modifying anything in each other.

How it works is view A sends a notification to a central hub from which view B hears said notification. When view B hears the notification it activates, and calls a function defined by the user.

For a more detailed explanation, you can refer to: https://learnappmaking.com/notification-center-how-to-swift/

Related