Search code examples
iosswiftdependency-injectiontyphoon

Typhoon initializer injection & calling super.init()


I have a parent and child class and an initializer in the child class that accepts some parameters and then calls super.init() to initialize the properties from the base class.

As I have a lot of child classes I want to reuse code for injecting the parameters but I can't figure out a way of injecting some of the members in the base class definition and the rest of them in the child class definition.

I tried the following:

public dynamic func baseManager() -> AnyObject {
    return TyphoonDefinition.withClass(BaseManager.self) {
        (definition) in

        definition.useInitializer("initWithBaseParam1:baseParam2:") {
            (initializer) in

            initializer.injectParameterWith(self.baseParam1())
            initializer.injectParameterWith(self.baseParam2())
        }
    }
}

public dynamic func authenticationManager() -> AnyObject {

    return TyphoonDefinition.withClass(AuthenticationManager.self) {
        (definition) in

        definition.parent = self.baseManager()
        definition.useInitializer("initWithChildParam1:childParam2:baseParam1:baseParam2:") {
            (initializer) in

            initializer.injectParameterWith(self.childParam1())
            initializer.injectParameterWith(self.childParam2())
        }
    }
}

But I get an error that I use an initializer with 4 parameters but only inject 2 of them. Is there a way I can make this work or do I have to refactor the base params to be properties like the example in the docs?


Solution

  • You can inherit the initializer from a parent or override it, but unfortunately you can't extend an initializer with extra parameters in addition to those defined in a parent template.

    Suggested alternatives:

    Use Property Injection

    Generally we recommend to favor initializer injection it allows the creation of immutable objects and state verification after construction. These drawbacks in property injection can be addressed by:

    • Specify a callback method to be used after properties have been injected.
    • For instances that are designed to be immutable, declare properties as internally read-write, but externally read-only.

    Use composition rather than inheritance

    Another suggestion is to create an appropriately scoped definition that encapsulates the configuration that tends to be used together and inject that.

    Depending on the situation this can be advantageous - there's lots of good articles around on 'composition vs inheritance' and when each is appropriate.