Swinject: Inject runtime arguments when resolving circular dependencies

Created on 13 Apr 2017  路  7Comments  路  Source: Swinject/Swinject

Hello guys,

I investigated a possibility to pass arguments if I had circular dependencies. For example I have 3 objects which links each other:

  • view <->presenter, presenter <->interactor, interactor->view
protocol LoginViewInput {}

protocol LoginViewOutput {
    func didTriggerViewDidLoad()
}

protocol LoginInteractorInput {
    func executeRequest()
}

class LoginViewController: UIViewController, LoginViewInput {
    var output: LoginViewOutput?
    var key: String?

    override func viewDidLoad() {
        super.viewDidLoad()

        print("inject view key: \(key)")
        self.output?.didTriggerViewDidLoad()
    }
}

class LoginPresenter: LoginViewOutput {
    var view: LoginViewInput?
    var interactor: LoginInteractorInput?
    var key: String?

    func didTriggerViewDidLoad() {
        print("inject presenter key: \(key)")
        self.interactor?.executeRequest()
    }
}

class LoginInteractor: LoginInteractorInput {
    var output: LoginViewOutput?
    var view: LoginViewInput?
    var key: String?

    func executeRequest() {
        print("inject interactor key: \(key)")
    }
}

So in my business code I'd like to inject some object when resolving dependencies.

let view = self.mainAssembler?.resolver.resolve(LoginViewInput.self, argument: "awesome version parameter")

I wrote the following Assembly.

class LoginAssembly: Assembly {
    func assemble(container: Container) {
        container.register(LoginViewInput.self) { (r, version: String) in
            let controller = LoginViewController(nibName: "LoginViewController", bundle: nil)
            controller.key = version
            return controller
        }.initCompleted { r, i in
            let controller = i as! LoginViewController
            controller.output = r.resolve(LoginViewOutput.self)
            // possible I need to write here something like this
            // controller.output = r.resolve(LoginViewOutput.self, argument: version)
        }

        container.register(LoginViewOutput.self) { (_, version: String) in
            let presenter = LoginPresenter()
            presenter.key = version
            return presenter
        }.initCompleted { r, i in
            let presenter = i as! LoginPresenter
            presenter.view = r.resolve(LoginViewInput.self)
            presenter.interactor = r.resolve(LoginInteractorInput.self)
            // possible I need to write here something like this
            // presenter.interactor = r.resolve(LoginInteractorInput.self, argument: version)
            // presenter.view = r.resolve(LoginViewInput.self, argument: version) 
        }

        container.register(LoginInteractorInput.self) { (_, version: String) in
            let interactor = LoginInteractor()
            interactor.key = version
            return interactor
        }.initCompleted { r, i in
            let interactor = i as! LoginInteractor
            interactor.output = r.resolve(LoginViewOutput.self)
            interactor.view = r.resolve(LoginViewInput.self)
            // possible I need to write here something like this
            // interactor.output = r.resolve(LoginViewOutput.self, argument: version)
            // interactor.view = r.resolve(LoginViewInput.self, argument: version)
        }
    }
}

But I don't know how to pass version parameter in initCompleted block to resolve dependencies. Does anybody know how to resolve it? Thank you in advance!

question

Most helpful comment

@igorkotkovets
try create new variable after:
func assemble(container: Container)

like:

    func assemble(container: Container) {
    var argument: String?
    container.register(LoginViewOutput.self) { (resolver: Resolver, version: String) in
            let presenter = LoginPresenter()
            presenter.key = version
            argument = version // save runtime argument 
            return presenter
    }.initCompleted { (resolver, presenter) in
            let presenter = presenter  as? LoginPresenter
            let version = argument! // get runtime argument
            presenter?.interactor = r.resolve(LoginInteractorInput.self, argument: version)
            presenter?.view = r.resolve(LoginViewInput.self, argument: version) 
            presenter?.key = version
    }

All 7 comments

Hi @igorkotkovets! Let me take time to read your code. Thanks!

@yoichitgy Great! I'm waiting for your feedback!

@yoichitgy be free to ask me if you need more details.
What if Resolver object will grab runtime arguments somehow explicitly and they will be accessible in initComplented block?
Plz look on dummy code below. I don't know how Resolver will store runtime argument, just my thoughts

container.register(LoginViewOutput.self) { (resolver: Resolver, version: String) in
            let presenter = LoginPresenter()
            presenter.key = version
            resolver.save(version) // save runtime argument 
            return presenter
}.initCompleted { (resolver, presenter) in
            let presenter = presenter  as? LoginPresenter
            let version = resolver.get() // get runtime argument
            presenter?.interactor = r.resolve(LoginInteractorInput.self, argument: version)
            presenter?.view = r.resolve(LoginViewInput.self, argument: version) 
            presenter?.key = version
}

Thanks @igorkotkovets. I already have a lot of question issues in this project, so I will come back here after answering the questions.

@igorkotkovets
try create new variable after:
func assemble(container: Container)

like:

    func assemble(container: Container) {
    var argument: String?
    container.register(LoginViewOutput.self) { (resolver: Resolver, version: String) in
            let presenter = LoginPresenter()
            presenter.key = version
            argument = version // save runtime argument 
            return presenter
    }.initCompleted { (resolver, presenter) in
            let presenter = presenter  as? LoginPresenter
            let version = argument! // get runtime argument
            presenter?.interactor = r.resolve(LoginInteractorInput.self, argument: version)
            presenter?.view = r.resolve(LoginViewInput.self, argument: version) 
            presenter?.key = version
    }

@makleso6 thank you, I'll check

Thanks @makleso6 for your answer馃槂馃憤馃槂馃憤馃槂馃憤

Was this page helpful?
0 / 5 - 0 ratings

Related issues

oronbz picture oronbz  路  3Comments

igorkotkovets picture igorkotkovets  路  7Comments

sialcasa picture sialcasa  路  5Comments

diwengrum picture diwengrum  路  5Comments

J7mbo picture J7mbo  路  5Comments