Presenting a view from another module without importing the module

Hey everyone,

I have a modular UIKit app that i am migrating to SwiftUI/TCA currently. I have two flow modules that are already migrated to SwfitUI/TCA and i want to present some screen in Module-A from Module-B but i naturally don't want to import Module-B to Module-A.

In my main project i have my structure on UIKit tabbar so, i am not able to present the view from Module-B with the MainView since i don't have one.

My question is how can i present this SwiftUI/TCA view from Module-B from my Module-A properly without using UIKit hosting controllers since both modules live in the SwiftUI realm.

Thank you in advance!

Hi @Yasin !
Maybe you want to create a Main/Core module to set modules A and B as dependencies and then consume them as you need?

Hey @otondin, thanks for the reply.

I already have imported both these modules on my main target but can't figure out the way of presenting that view from Module-B inside Module-A without Module-A knowing anything about it. If i had the SwiftUI MainView with TCA, i could be able to present it in there.

Can you draw a pseudo project-tree to illustrate better what you're aiming for?

One of options is to define closure variable in Module-A var navigateModuleBViewContoller(...) -> UIViewController and inject it in main target at moment you create both modules. Not you can use this closure to build ViewController and perform navigation.

@Yasin I was re-thinking about it and maybe another way to accomplish a decoupled navigation would be to implement a stack-base navigation approach. Also, if you're Point Free subscriber, this episode can help you to understand how to implement the stack-based navigation.

Hey Andriy, thank you for reply but i wanna handle this pure SwiftUI/TCA way instead of presenting a view controller again.

Hey @otondin, thank you for giving it a second thought. I am a Point free subscriber and will check the episodes :pray:

1 Like

In A framework you have a view goes by AView.
and you have B framework,and a BaseFramework for both of them.

In BaseFramework,you have protocol maybe

protocol Sharing {
associatedtype FromAView: View
func makeFromAView() -> FromAView
}

in B framework,use protocol like

struct BView<Sharer: Sharing>: View {
init(sharer: Sharer) { … }
var body: some View {
sharer.makeFromAView()
}
}

In main project
struct Sharer: Sharing {
func makeFromAView() -> some View {
AView()
}
}

Use BView(sharer: Sharer())

Edit by iPhone, maybe format issue

If you dont want use Generics and associatedtype, you have to use AnyView for it

Hey @xiaozao2008 thanks for the reply man but since its TCA the parent view also needs to know about the state of the child view. Thats the problem i can't fix man.

This isn't really a TCA-specific problem. You would have the same problem in vanilla SwiftUI. If you have a ParentModel powering a ParentView that can present a ChildView powered by a ChildModel, then the easiest way to do that is to simply have ParentModel hold onto a ChildModel and ParentView present the ChildView using .sheet or some other view modifier.

If you want to break that coupling you have to do more work, such as introduce generics, but it does take work.