-
Notifications
You must be signed in to change notification settings - Fork 0
What can be Injected
##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.
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
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]];
}
Something still not clear? How about posting a question on StackOverflow.
Get started in two minutes.
Get familiar with Typhoon.
- [Types of Injections](Types of Injections)
- [What can be Injected](What can be Injected)
- Auto-injection (Objective-C)
- Scopes
- Storyboards
- TyphoonLoadedView
- Activating Assemblies
Become a Typhoon expert.
For contributors or the just plain curious.