Skip to content

What can be Injected

jasperblues edited this page Dec 23, 2014 · 67 revisions

[Types of Injections](Types of Injections) | What can be Injected | Modularizing Assemblies | Scopes | Activating Assemblies | Storyboards | [Integration Testing](Integration Testing)

##A definition can be injected with . . .

#Other Definitions

The most common scenario is of course that a definition wishes to be injected with the built instance of another definition.

By Type

For properties, the Objective-C run-time provides type-introspection. Therefore, injection can be done by matching the required-type, as follows:

- (Knight *)knight
{
    return [TyphoonDefinition withClass:[Knight class] configuration:^(TyphoonDefinition *definition) {
        [definition injectProperty:@selector(quest)];
    }];
} 

NB: When injecting by type, Typhoon searches within the bounds of the TyphoonComponentFactory, so it can match components declared in [other assemblies](Modularizing Assemblies)

. . Typhoon will find the component that matches the required type.

see also: Autowiring

By Reference

Injection can be done by reference. This is useful in the common requirement you have multiple components matching the same class or protocol. The injection is done by referencing a method in the assembly, meaning you can use all of your IDE refactoring tools, as you normally would.

- (Knight *)knight
{
    return [TyphoonDefinition withClass:[Knight class] configuration:^(TyphoonDefinition *definition) {
        [definition injectProperty:@selector(quest) with:[self defaultQuest]];
    }];
}

- (Knight *)knightWithQuestFromAnotherModule
{
    return [TyphoonDefinition withClass:[Knight class] configuration:^(TyphoonDefinition *definition) {
        [definition injectProperty:@selector(quest) with:[_questModule scaryQuest]];
    }];
}

see also: Modularizing Assemblies

NB: By focusing on 'by type' style injection, other DI containers incorrectly assume that all objects of a given type will be configured the same way, requiring a lot of configuration when this is not the case. Typhoon, on the other hand, makes this easy, at the same time as supporting IDE checks and code-copmletion, and without using 'magic strings'


#Injecting Typhoon Itself

Typhoon can inject itself. This is useful in order to proceed from one object-graph to another, for example, loading a new view controller to proceed to from the existing one. When injecting Typhoon itself, the property or method parameter can be of type TyphoonComponentFactory, any one of your assembly interfaces or a protocol representing one of your assembly interfaces. (So there's no worry about coupling your application directly to Typhoon).


- (RootViewController *)rootController
{
    return [TyphoonDefinition withClass:[RootViewController class] configuration:^(TyphoonDefinition* definition)
    {
        [definition injectProperty:@selector(assembly)];
    }];
}

The assembly can be injected either by type, as shown above, or explicitly:

[definition injectProperty:@selector(assembly) with:self];

Injecting a collaborating assembly: (see Modules)

[definition injectProperty:@selector(assembly) with:self.networkComponents];

. . similarly, the assembly can be injected into initializers, properties or methods.


As an alternative, if you're not worried about your class having a direct dependency on Typhoon, you can also do the following:

#import Typhoon.h

- (void)typhoonSetFactory:(id)theFactory
{
    //_factory is of type TyphoonComponentFactory, but can be cast to any of your 
    //TyphoonAssembly sub-classes, if desired. 
    _factory = theFactory;
}


#Injecting Configuration

Besides injecting other Typhoon-built components, Typhoon can perform configuration by injecting simple objects and primitive values.

###Injecting a Simple Object

[definition injectProperty:@selector(serviceUrl) with:
    [NSURL URLWithString:@"http://www.myapp.com/service"]]; 

###Using Auto-boxing / NSValue to inject primitives

Primitives can be injected using auto-boxing. C-style strings and structs can be injected as an NSValue, Typhoon will unpack the value onto the object instance.

[initializer injectParameterWith:@(NSPrivateQueueConcurrencyType)]; 
[initializer injectParameterWith:@(INT_MAX)];
[initializer injectParameterWith:@YES];
[initializer injectParameterWith:[SomeClass class]];
[initializer injectParameterWith:NSValueFromPrimitive(@selector(selectorValue))];
const char *cString = "Hello Typhoon";
[initializer injectParameterWith:NSValueFromPrimitive(cString)];
[initializer injectParameterWith:[NSValue valueWithRange:NSMakeRange(10, 20)]];
[initializer injectParameterWith:[NSValue valueWithPointer:primitiveStruct]];

More examples of injecting primitives with NSValue: wrap-primitive-values-into-NSValue

##Typhoon Config

If you wish, configuration information can also be extracted into a properties file that can be stored locally or resolved dynamically.

####Create a properties file with the values, as follows:

#for primitive values just write the property value
damsels.rescued=12
hasHorseWillTravel=no

#for object instances, declare the required type:
service.url=NSURL(http://my.backend.net/service-gateway)

####Attach your properties as follows:

to attach a properties file at run-time:

TyphoonConfigPostProcessor* configurer = [[TyphoonConfigPostProcessor alloc] init];
[configurer useResourceWithName:@"Configuration.properties"]];
[factory attachPostProcessor:configurer];

. . to attach a properties file at build-time

- (id)configurer
{
    return [TyphoonDefinition configDefinitionWithName:@"Configuration.properties"];}

. . And now reference a value as follows:

[definition injectProperty:@selector(serviceUrl) with:
    TyphoonConfig(@"service.url")

####Supported formats for properties

Besides the .properties style of config shown above, the following formats are supported.

Plist (ie native Cocoa):

<plist version="1.0">
    <dict>
        <key>hasHorse</key>
        <true/>
        <key>damsels</key>
        <integer>28</integer>
    </dict>
</plist>

Json:

{
    "config": {
        "damsels_rescued": 42,
        "hasHorseWillTravel": true
    }
}

###Registering Type Converters

In the properties file above, we declare the required type and define will convert our value for us. Typhoon contains pre-built type converters, or you can register your own, as follows:

Create a class that conforms to the following:

@protocol TyphoonTypeConverter <NSObject>

- (id)supportedType;

- (id)convert:(NSString*)stringValue;

@end

. . . And then register it with the container as follows:

- (id)myTypeConverter
{
    //Will participate as a type converter as it conforms to the required protocol. 
    return [TyphoonDefinition withClass:[YourConverterClass class]];
}



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 the just plain curious.

Clone this wiki locally