iosswifttyphoon

Typhoon: Inject subclass property into definition from withFactory:selector: injection style


I am using Typhoon to inject dependencies into a subclass of UIViewController. I've found a potential solution to a different question i had which involves doing instantiation of the view controller using the "factory" injection method:

return TyphoonDefinition.withFactory(self.storyboard(), selector:"instantiateViewControllerWithIdentifier:", parameters: { (method) in
            method.injectParameterWith("camera-mode-controller")
        }, configuration: { (definition) in
            definition.injectProperty("cameraProvider", with: self.systemComponents.systemCameraProvider())
    })

However, the UIStoryboard signature func instantiateViewControllerWithIdentifier(identifier: String) -> UIViewController indicates that this factory method initializer will create a UIViewController, which does not have the property of my subclass (dynamic var cameraProvider). Therefore, at runtime, the property injection fails with setter not found.

Is there a way to say something like, "create definition with class: and factory: with method: and properties", so that the definition knows the class it is producing is not a UIViewController but in fact, in my case, a CameraModeViewController: UIViewController? Digging in the API docs I see, TyphoonDefinition.withParent:class:configuration: might chainable with the withFactory:selector:parameters: method to produce this effect? However, my attempt:

public dynamic func viewControllerFromID(id: String) -> AnyObject {
    return TyphoonDefinition.withFactory(self.storyboard(), selector: "instantiateViewControllerWithIdentifier:") {
        (method) in
        method.injectParameterWith(id)
    }
}

public dynamic func cameraModeViewController() -> AnyObject {
    return TyphoonDefinition.withParent(self.viewControllerFromID("camera-mode-controller"), `class`: CameraModeViewController.self) {
        (definition) in
        definition.injectProperty("cameraProvider", with: self.systemComponents.systemCameraProvider())
    }
}

produces the error: 'You can't call a method on the runtime argument being passed in. It has to be passed in as-is' in -[TyphoonInjectionByRuntimeArgument forwardingTargetForSelector:] with selector argument "length". Any thoughts?


Solution

  • I solved this problem for myself: due to a version control problem, the storyboard member with that identifier had forgotten its UIViewController subclass assignment, and as such was NOT in fact castable, and did not have that property. As it turns out, Typhoon works just fine with injecting properties declared in view controller subclasses.