appsquickly / typhoon

Powerful dependency injection for Objective-C ✨✨ (https://PILGRIM.PH is the pure Swift successor to Typhoon!!)✨✨
https://pilgrim.ph
Apache License 2.0
2.7k stars 269 forks source link

Why is prototype scope not working? #462

Closed thefenix1 closed 7 years ago

thefenix1 commented 8 years ago

I have the following Typhoon configuration method inside an assembly

dynamic func myClassMapping() -> AnyObject {
    return TyphoonDefinition.withClass(MyClass.self) {
        (definition) in

        definition.scope = TyphoonScope.Prototype
    }
}

So far I understand, this should be causing no instance of MyClass to be resused. Despite of this, I'm seeing same instance injected (checked memory address on console) on different places. It's 100% checked that these places are different, not event the same class.

How could I make sure a new instance is always injected?

I've also created a question on stackoverflow in case that's a better place for this question.

I know that I might be missing information you could want to see but before pasting hundred of lines here I wanted to check if you have in mind any situation where Prototype scope doesn't behave as explained on wiki

Thanks

thefenix1 commented 8 years ago

I have created a demo project but I can't recreate it there, I can't send the full project but I'll continue trying to isolate this issue since it's a roadblock for me (the offending class is a ViewController, so application crash when same instance of ViewController is pushed twice on navigation controller)

Absolutely every single component on all assemblies are set to Prototype scope, nonetheless, this issue persist.

etolstoy commented 8 years ago

Hi, @thefenix1. Thanks for posting the issue.

This bug seems pretty odd. To investigate it properly we need a demo project, where this issue is reproducing. Besides it, can you post the full definition for your ViewController? Are you using storyboards integration?

thefenix1 commented 8 years ago

I have a demo project but unfortunately I couldn't recreate it there yet. I'll keep trying.

I'm using storyboard integration and here you have view controller defintion

dynamic func eventDetailViewController() -> AnyObject {
    return TyphoonDefinition.withFactory(self.applicationAssembly.mainStoryboard(), selector: "instantiateViewControllerWithIdentifier:", parameters: {
        (factoryMethod) in

        factoryMethod.injectParameterWith("EventDetailViewController")
        }, configuration: {
            (definition) in
            definition.injectProperty("presenter", with: self.eventDetailPresenter())
            definition.scope = TyphoonScope.Prototype
    })
}
thefenix1 commented 8 years ago

I was sidetracked to a different project but now I'm back into this and won't leave it until is solved :)

I'm still unable to recreate it on my test project and unfortunately I can't send the entire project for you to validate it. Probably doesn't help very much but here you have memory addresses pattern (last 4 positions of the memory address).

First column is injected instance (class A) and second is the "parent" instance (class B). Notice that after the first injection it starts repeating injected instance in pairs. EVERYTHING is set to scope prototype. This list is sorted by injection time.

ce00 5080 5c00 9690 5c00 9e70 4000 a420 4000 5830 0000 ded0 0000 4300 5800 bcd0 5800 ab00

Thanks

thefenix1 commented 8 years ago

On this method on class TyphoonInjectionByReference many times referenceInstance is not null and I understand it should be null for prototype scope so it creates them every time. Hopefully I'm not getting something wrong

- (id)resolveReferenceWithContext:(TyphoonInjectionContext *)context
{
    TyphoonRuntimeArguments *args = [TyphoonRuntimeArguments argumentsFromRuntimeArguments:context.args appliedToReferenceArguments:_referenceArguments];

    id referenceInstance = [[[context.factory stack] peekForKey:self.reference args:args] instance];
    if (!referenceInstance) {
        referenceInstance = [context.factory componentForKey:self.reference args:args];
    }
    return referenceInstance;
}

I feel dizzy but probably my issue is related with a loop of references since that's why stack already contains an instance.

thefenix1 commented 8 years ago

You can close this reference loop perfectly explains what I see. Obviusly you have to cut the loop in some way to avoid an infinite injection process. Sorry for not catching this and thanks for the support.

etolstoy commented 8 years ago

Still no success in recreating it in demo project?

etolstoy commented 7 years ago

Closing due to inactivity. If you still experience this issue, feel free to reopen it.