Closed Narayane closed 5 years ago
The difference between shared
and singleton
scope is that shared
only shares instances in the same dependencies graph. That said, after top-most resolve
method returns next resolve
will produce new instances for shared
scope but will reuse previously created instances for singleton
scope. So to use shared
scope you need to resolve you graph at once, not later at runtime when push happens.
That said you need to create a graph that will be able to create a second view controller when you push it. You can use factories/builders for that, that you can resolve as part of the dependencies in the beginning and that will have reference to view model that they will pass to view controller that they create lazily at runtime.
self.register(.singleton) { try Repository(graphQL: self.resolve(), fileStorage: self.resolve()) as RepositoryProtocol }
self.register(type: SharedViewModelProtocol.self, factory: SharedViewModel.init)
self.register(storyboardType: AViewController.self, tag: "A")
.resolvingProperties { container, vc in
vc.viewModel = try container.resolve() as SharedViewModelProtocol
}
self.register(storyboardType: BViewController.self, tag: "B")
.resolvingProperties { container, vc in
vc.viewModel = try container.resolve() as SharedViewModelProtocol
}
Like this? Because same effect than previous code, VM instance is always not shared.
It's not about registration, it's about how you resolve dependencies for the second view controller. They should be resolved when you resolve the first view controller that will later push the second.
When using storyboard registration it will resolve view controller properties only when it is created from xib, so it will not be the new objects graph.
So with this you either need to use singleton
scope or switch from registering second vc with storyboard registration to creating it in code via factory. You can still create it from a storyboard but the factory should already have all the properties this vc needs and should inject them.
class VCFactory {
let viewModel: SharedViewModelProtocol
func createSecondVC() -> UIViewController {
let vc = Storyboard.instantiateViewController...
vc.viewModel = viewModel
return vc
}
}
register(type: SharedViewModelProtocol.self, factory: SharedViewModel.init)
register(factory: VCFactory.init)
self.register(storyboardType: AViewController.self, tag: "A")
.resolvingProperties { container, vc in
vc.viewModel = try container.resolve() as SharedViewModelProtocol
vc.factory = try container.resolve() as VCFactory
}
Would it be technically possible to have a "real" shared scope for a given object instance between different dependencies resolution graphs?
that's what singleton
scope is for 🤷♂️ you maybe can use weakSingleton
if you need to recreate an instance at some point.
Technically not. For me, singleton scope lasts while dip container exists whereas shared scope "as I hear" lasts while at least one dependencies graph references it.
what you described is a weekSingleton
=)
@ilyapuchka It seems indeed. In my mind, this scope was only useful for breaking singletons cyclic injections... but I have one question again :)
I observe this:
Resolved type SharedViewModelProtocol with SharedViewModel
Reusing previously resolved instance SharedViewModel
that it is perfect!Reusing previously resolved instance SharedViewModel
that I don't want, I want a fresh instance of my SharedViewModelSo, how can I force your you maybe can use weakSingleton if you need to recreate an instance at some point at each AViewController dependencies graph new resolution?
self.register(.singleton) { try Repository(graphQL: self.resolve(), fileStorage: self.resolve()) as RepositoryProtocol }
self.register(.weakSingleton) { try SharedViewModel(repository: self.resolve()) as SharedViewModelProtocol }
self.register(storyboardType: AViewController.self, tag: "A")
.resolvingProperties { container, vc in
vc.viewModel = try container.resolve() as SharedViewModelProtocol
}
self.register(storyboardType: BViewController.self, tag: "B")
.resolvingProperties { container, vc in
vc.viewModel = try container.resolve() as SharedViewModelProtocol
}
@ilyapuchka?
@Narayane you should probably register two weakSingleton
s of your view model with different tags, maybe reusing tags you use for view controllers. Then when you resolve the second stack when you need to resolve this new view model you need to use a different tag and then the new instance will be created and associated with this tag.
Hi,
I want to share the same instance of a view model between 2 view controllers. But I don't know how to inject it in them without call resolve() function that "reinit" my view model object instance according to this
Here, part of my Dip container:
When I load my AViewController, Dip logs:
Then when I push my BViewController from AViewController, Dip logs:
I don't want to update the view model scope to .singleton because it is not: just a "shared" object for a determinated time
Thanks for helping me