Skip to content

1.x_Assembling Components in XML

Jasper Blues edited this page Apr 26, 2014 · 5 revisions

Block Assembly | Xml Assembly | Autowiring | Using-assembled-components | Installing | Configuration-Management-&-Testing


About XML Style Assembly

If you're familiar with the Spring Framework - the popular Dependency Injection Framework for Java, .NET and ActionScript, then the XML-style of assembly will feel very familiar. As yet, the XML-style doesn't provide as deep IDE integration as the block-style, which is why the block-style remains the recommended approach.

Code Completion

Basic code-completion is provided, initially with an XML schema. This works in AppCode, but the Xcode XML editor doesn't resolve schemas, it seems. To get the code completion, declare the XML-schema, like so:

<assembly xmlns="http://www.typhoonframework.org/schema/assembly"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.typhoonframework.org/schema/assembly
          http://www.typhoonframework.org/schema/assembly.xsd">

Properties injected by reference:

You can declare a component that has another component injected via a property setter. The container will look up the component matching the required key. This feature is useful when you want to have multiple implementations of a protocol.

<component class="Knight" key="knight">
    <property name="quest" ref="quest"/>      
</component>

### Properties injected by value:

Properties can be injected by value. The container will look up the required class or primitive type. It's easy to register your own additional converters.

This makes it possible to have components configured for eg "Test" vs. "Production" scenarios and provides a good compromise between pure unit testing and integration testing.

<component class="Knight" key="knight">
    <property name="damselsRescued" value="12"/>
    <property name="imageUrl" value="http://www.appsquick.ly/theQuest.jpg"/>
</component>

Collections

A property of type NSSet or NSArray can be populated as follows:

<property name="menuItems">
    <collection>
        <!-- Populate the property with components matching the 'ref' name -->
        <ref>menuItemMyTrips</ref>
        <ref>menuItemContact</ref>
        <!-- Use Typhoon's type converter system to convert the string representation -->
        <value requiredType="NSString">mary</value>
        <value requiredType="NSNumber">12</value>
    </collection>
</property>

### Property injection call-backs:

The container provides a way to invoke a method before or after property injection, to ensure that the instance is in the required state before receiving collaborating classes.

For example, in the case of a RootViewController, you can assert that root controller's view is not nil, before injecting child view controllers.

<component class="CampaignQuest" before-property-injection="questBeforePropertyInjection"
           after-property-injection="questAfterPropertyInjection"/>

As an alternative to declaring the property injection methods in the assembly, if you're not worried about your class having a direct dependency on Typhoon, you can also implement the following protocol:

@protocol TyphoonPropertyInjectionDelegate <NSObject>

Circular Dependencies

Sometimes you wish to define components that depend on each other. For example a ViewController that is injected with a view, and a View that is injected with the ViewController as a delegate.

This is possible using property-style injection, but not for initializer injection.

Initializer Injection

Besides property injection, initializer injection is supported.

Note that for initializer injection, if you want to supply values you must supply the required class, unless the type is a primitive (because the objective-C runtime doesn't supply type introspection on method parameters).

<component class="CavalryMan" key="anotherKnight">
    <initializer selector="initWithQuest:">
        <argument parameterName="quest" ref="quest"/>
        <argument parameterName="hasHorseWillTravel" value="12"/>
        <argument parameterName="imageUrl" value="http://www.appsquick.ly" required-class="NSURL" />
    </initializer>    
</component>

Class Methods vs Init Methods

Initializer injection can be used for both alloc'd and auto-release/class style methods. As long as the method follows normal naming conventions, the container will guess weather it's a class method or alloc init'd method. This can be over-ridden with the 'is-class-method' attribute. The default value is 'guess'. Acceptable values are: {'guess', 'yes/true', 'no/false'}.

<component class="NSURL" key="serviceUrl">
    <initializer selector="URLWithString:" is-class-method="yes">
        <argument parameterName="string" value="http://dev.foobar.com/service/" required-class="NSString"/>
    </initializer>
</component>

Factory Component Injection

Sometimes you have a component, such as one from a 3rd party library that produces a configurable instance that you'd like to inject as a dependency in other components. You can do this using a factory component:

<component class="SwordFactory" key="swordFactory"/>

<component class="Sword" key="blueSword" factory-component="swordFactory">
    <initializer selector="swordWithSpecification:">
        <argument parameterName="specification" value="blue" required-class="NSString"/>
    </initializer>
</component>

Scopes

  • The default scope is 'TyphoonScopeObjectGraph' - a scope that is (as far as we know) unique among DI containers. This scope is especially geared towards mobile and desktop applications. When a component is resolved, any dependencies with the object-graph will be treated as shared instances during resolution. Once resolution is complete they are not retained by the TyphoonComponentFactory. This allows instantiating an entire object graph for a use-case (say for a ViewController), and then discarding it when that use-case has completed.
  • The prototype scope means that a new instance will always be created by Typhoon.
  • The singleton scope means that Typhoon will retain the instance that exists for as long as the TyphoonComponentFactory exists.
  • The weakSingleton scope works the same as singleton, except that not components are currently using the singleton, it will be destroyed. A subsequent request will have it created again.
<component class="Knight" key="knight" scope="singleton">
    <property name="quest" ref="quest"/>      
</component>

githalytics.com alpha

Quick Start!

Get started in two minutes.

Main Track

Get familiar with Typhoon.

Advanced Topics

Become a Typhoon expert.

Under the Hood

For contributors or curious folks.

Clone this wiki locally