0

I have an iOS project written in SwiftUI but the navigation is handled with UIKit. Therefore each view has its own UIHostingController which takes care of initializing the view written in SwiftUI within its init(), for example:

final class ExampleViewController: UIHostingController<ExampleView> {
    
    required init?(coder: NSCoder) {
        super.init(coder: coder, rootView: ExampleView(viewModel: .init(model: nil)))
    }
    
    init(model: ExampleModel) {
        super.init(rootView: ExampleView(viewModel: .init(model: model)))
    }
}

Where ExampleView is something like:

struct ExampleView: View {
    @StateObject var viewModel: ExampleViewModel
    
    var body: some View {
       VStack {
          // Content
       }
    }
}

My doubt arises when I have to share data that can be updated from different views, I'll give a practical example:

I have a view that shows a list of tasks and a view that shows the detail. In the task detail user can change, for example, the name and status of the task (todo, inProgress and completed) of the element and and when these are modified should also change in the list without updating the data via APIs.

How can I achieve this without using callbacks, delegates or notifications but taking advantage of the tools available with SwiftUI? Is it possible even if navigation is managed with UIKIT?

I did several tests by sharing the @Published data array between the view models but I don't understand why the changes are not reflected in the UI of the list although the data is updated, so I was wondering if it was possible.

1 Answer 1

0

In SwiftUI the View struct is the view model you shouldn’t be misusing Combine's @StateObject to do the same thing. When you have your new data in UIKit just replace the rootView with a new View struct that was init with the new data, body is called when the data has changed (even if it is a let).

If you want SwiftUI to update the model you can pass it the store as an environment object.

Here are some examples:

// pass in new read-only value
hostingController.rootView = ContentView(param: newValue) 
// declare let param in ContentView.

// passing data back via callback 
hostingController.rootView = ContentView() { newValue
    // newValue changed
}
// declare let callback: (() -> (Int)) in ContentView.

// passing in store to load/save from
hostingController.rootView = NewContentView(modelID: model.id).environmentObject(modelStore)
Sign up to request clarification or add additional context in comments.

2 Comments

Could u provide me a simple example? I would like to better understand how to implement this tip to achieve what I would like to do
Sure, hostingController.rootView = NewContentView(orNewParam: bla)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.