Weaver icon indicating copy to clipboard operation
Weaver copied to clipboard

Fix dependency resolver ordering

Open StephaneMagne opened this issue 3 years ago • 0 comments

This makes a change to how we manage the _dynamicResolvers array.

The old code popped from the front:

    fileprivate static func _popDynamicResolver<Resolver>(_ resolverType: Resolver.Type) -> Resolver {
        guard let dynamicResolver = _dynamicResolvers.removeFirst() as? Resolver else {
            MainDependencyContainer.fatalError()
        }
        return dynamicResolver
    }

And I've updated this to pop from the back:

    fileprivate static func _popDynamicResolver<Resolver>(_ resolverType: Resolver.Type) -> Resolver {
        guard let dynamicResolver = _dynamicResolvers.removeLast() as? Resolver else {
            MainDependencyContainer.fatalError()
        }
        return dynamicResolver
    }

And to support this, I've inverted the ordering of how the dependencies are pushed.

Here's the use case of the Repository class being built

        _builders["repository"] = Provider.lazyBuilder(
             { (_: Optional<Provider.ParametersCopier>) -> RepositoryProtocol in
                defer { MainDependencyContainer._dynamicResolversLock.unlock() }
                MainDependencyContainer._dynamicResolversLock.lock()
                let _inputContainer = MainDependencyContainer(provider: _inputProvider)
                let __self = _inputContainer.repositoryDependencyResolver()
                return Repository(injecting: __self)
            }
        )

This calls the function repositoryDependencyResolver() which pushes the dependency resolvers. To make sure we pop these off the stack correctly, we push them on in reverse order (so the first one we attempt to access is on the end).

Here's a look at the changes to the repositoryDependencyResolver() function...

Old:

    private func repositoryDependencyResolver() -> RepositoryDependencyResolver {
        let _self = MainDependencyContainer()
        var _builders = Dictionary<String, Any>()
        _builders["repositoryExampleSubClass"] = repositoryExampleSubClassBuilder
        _builders["service"] = serviceBuilder
        _builders["service2"] = service2Builder
        _self.provider.addBuilders(_builders)
        MainDependencyContainer._pushDynamicResolver({ _self.service })
        MainDependencyContainer._pushDynamicResolver({ _self.service2 })
        MainDependencyContainer._pushDynamicResolver({ _self.repositoryExampleSubClass })
        return _self
    }

New:

    private func repositoryDependencyResolver() -> RepositoryDependencyResolver {
        let _self = MainDependencyContainer()
        var _builders = Dictionary<String, Any>()
        _builders["repositoryExampleSubClass"] = repositoryExampleSubClassBuilder
        _builders["service"] = serviceBuilder
        _builders["service2"] = service2Builder
        _self.provider.addBuilders(_builders)
        MainDependencyContainer._pushDynamicResolver({ _self.repositoryExampleSubClass })
        MainDependencyContainer._pushDynamicResolver({ _self.service2 })
        MainDependencyContainer._pushDynamicResolver({ _self.service })
        return _self
    }

StephaneMagne avatar Jun 09 '22 21:06 StephaneMagne