New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SwiftUI Previews only working in the main app of multi framework application #114
Comments
I can't give you a good answer to that question because I don't have a good idea as to how the dependencies run. That said, my first idea would be to register each frameworks objects in its own container, then wire together the containers in the main application. Look at the following issue that shows using containers in SwiftUI previews and see if that helps. |
Thank you for your fast answer! But I saw an answer from you which sounds interesting but I don't understand it completely. A more simple project setup where the same error occurs is the following: As soon as you're previewing one of the views in the framework Resolver won't find the registrations done in the application because only the framework gets executed. While writing this I noticed that even without using Resolver and instead constructor dependency injection this would never work, because I can't access the class of the application from the framework. There I can only access the protocol but I can make the class only conform to the protocol from the application but this won't be possible if running a preview inside the framework. Now the only way I can think of to make this work is to make the framework which I want the previews to work the highest in the dependency chain. In my setup the easiest way is to make the Presentation layer depend on the Data layer. This isn't a nice approach as this destroys kind of the complete project architecture. But if this is the only working way, I will go it. Furthermore I then will use the approaches from issue 72 to mock my view models. Maybe you could explain the approach with the "shared" package, otherwise the above will be my final solution. |
So this may not be everything, but it may help. The following project repository demonstrates using Resolver across frameworks and in the main application. https://github.com/hmlongco/ResolverFrameworksTest Functionally, the main trick is to place Resolver into its own, dedicated framework that's imported into the main application and into each individual framework. This is needed because If you simply include Resolver in each framework, then each framework has its own "copy" of Resolver that's a different type that all of the other copies of Resolver. I called that framework ResolverFramework in the example, but it could also be a common "SharedFramework" that contained a copy of Resolver plus other common code shared by the application. Either way, once that's done the main application would be responsible for calling the registration blocks for each framework the application wants to use. extension Resolver: ResolverRegistering {
public static func registerAllServices() {
registerAppServices()
registerPresentationServices()
}
} The example also shows defining a delegate protocol in the framework, and then fulfilling that protocol with a class registered in the main application. Hope this helps. |
Thank you for your help. Now I understand what you meant by using Resolver in a shared framework. I'm not sure if you didn't upload the To see if your approaches are applicable to my setup I recreated your work using multiple XcodeProjects in one Workspace and than the Preview feature for the
That's the same crash I always get when trying to preview a view that's not part of the framework in which the Resolver extension conforming to |
Um.... if you run the main app you're going to get something to to automatically call registerAllServices, which according to my demo will call each frameworks individual registerSomeServices function, right? So if you run a preview for a view in a framework, there's no registerAllServices to call, which means that nothing is registered, which means that nothing is found, which means... crash. As such, what I suspect that you need to do is explicitly call registerPresentationServices() (or whatever) in your preview function. I would try something like...
Where registerPreviewServices() is something like...
Note that the registerPreviewServices function is also calling the registration functions for any dependent frameworks. See if that gets us anywhere. (Note I tried being cute with an earlier version of this.) |
That's what I meant in my first post when writing
Your approach is like what I tried but the problem there is that I won't be able to register the |
So make it a protocol, mock it, and register that in registerPreviewServices as well?
Bottom line is that I really don't think you have any other choice, since you're in a framework and the delegate is going to come from outside of the framework. I mean, Resolver isn't magic. Even if you weren't using it and you were using, say, environment objects, you'd still have the same issue: How do I provide some instance of the data to the preview when I'm working in the standalone framework? |
Yes your totally right. |
I'm developing a SwiftUI app with a framework structure like in this picture. The Presentation, Domain and Data Layers are frameworks and the App Layer is the main app.
I'm registering all dependencies in the main app and it's working fine in simulator or real devices but in preview it gets tricky.
When previewing views of the main app (where all the dependencies get registered) everything is fine, too.
But when trying to preview views of the Presentation layer, the preview crashes because no dependencies are registered.
I think this happens because in preview not the complete app runs but only the framework (and it's sub frameworks) of the view your previewing gets executed. Therefore the ResolverRegistering extension doesn't run which registers the dependencies. (At least this would explain why it's only working in the preview of views implemented in the main app.)
I also tried to register all dependencies in the presentation layer but this only works for the dependencies implemented in this framework and not for these which are implemented in data framework, which the presentation framework has no access to.
So my question is how to make Resolver notice the dependencies registered in the main app from sub frameworks like presentation layer if running in preview mode?
The text was updated successfully, but these errors were encountered: