needle icon indicating copy to clipboard operation
needle copied to clipboard

How to solve circular dependency?

Open Ewg777 opened this issue 4 years ago • 6 comments

Here is an example of a component


class ABCComponent: Component<EmptyDependency>{


    var a: AProtocol {
        A(b)
    }

    var b: BProtocol {
        B(c)
    }

    var c: CProtocol {
        C(a)
    }


Now needle stucks in runtime try to resolve it. Is there a way to fix it? Thanks

Ewg777 avatar Sep 22 '21 13:09 Ewg777

Full example


@UIApplicationMain
final class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        registerProviderFactories()
        let rootComponent = RootComponent()
        let aaa = rootComponent.aaa
        print(aaa)
...

protocol AProtocol {
}

protocol BProtocol {
}

protocol CProtocol {
}

class A: AProtocol {
    init(b: BProtocol) {}
}

class B: BProtocol {
    init(c: CProtocol) {}
}

class C: CProtocol {
    init(a: AProtocol) {}
}

class ABCComponent: Component<EmptyDependency> {

    var a: AProtocol {
        A(b: b)
    }

    var b: BProtocol {
        B(c: c)
    }

    var c: CProtocol {
        C(a: a)
    }
}


final class RootComponent: BootstrapComponent {

    var abc: ABCComponent {
        ABCComponent(parent: self)
    }

    var aaa: AProtocol {
        abc.a
    }
}

Ewg777 avatar Sep 23 '21 05:09 Ewg777

Screenshot 2021-09-23 at 08 33 05

Ewg777 avatar Sep 23 '21 05:09 Ewg777

@rudro @neakor could you help please?

Ewg777 avatar Sep 23 '21 05:09 Ewg777

Thanks for the full example, but I don't think this has anything to do with Needle. Consider this code:

class ABCComponent {

    var a: AProtocol {
        A(b: b)
    }

    var b: BProtocol {
        B(c: c)
    }

    var c: CProtocol {
        C(a: a)
    }

     init() {}
}

let c = ABCComponent()
print(c.a)

Even if there's no Needle, this print statement will run into the same issue.

rudro avatar Oct 05 '21 17:10 rudro

@rudro thanks for your feedback! Let me give you one more example. Here is more realistic example. Please let me know if it's possible to resolve with Needle.

protocol ViewControllerProtocol: AnyObject {
}

protocol PresenterProtocol {
}

protocol RouterProtocol {
}

class AViewController: ViewControllerProtocol {
    var presenter: PresenterProtocol!
}

class Presenter: PresenterProtocol {
    var router: RouterProtocol!
}

class Router: RouterProtocol {
    weak var controller: ViewControllerProtocol?

    init(controller: ViewControllerProtocol) {
        self.controller = controller
    }
}

class ABCComponent {

    var aViewController: ViewControllerProtocol!
}

Ewg777 avatar Oct 06 '21 06:10 Ewg777

Legit question. It's of course not possible to resolve circular dependency statically (by the very nature of the problem), but usually these use cases can be dealt with the usage of lazy injection, i.e. one of the dependencies in the circle is not resolved statically, but only injected upon usage. Needle seems to be inspired by dagger somewhat, so this link might help.

micHar avatar Dec 02 '21 12:12 micHar