-
Notifications
You must be signed in to change notification settings - Fork 269
What can be Injected
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: Auto Injection
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 quest]];
}];
}
- (id<Quest>)quest
{
return [TyphoonDefinition withClass:[SaveTheKingdomQuestImpl class]];
}
see also: Modularizing Assemblies
Typhoon assemblies can be injected. 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.
- The property or method parameter can be of type
TyphoonComponentFactory
- The property can be any one of your
TyphoonAssembly
sub-classes (or if you wish, a protocol that represents these).
- (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 Modularizing Assemblies)
[definition injectProperty:@selector(assembly) with:self.networkComponents];
. . similarly, the assembly can be injected into initializers, properties or methods.
We can then use this injected assembly to retrieve built instances from Typhoon 'on-demand', for example:
NewViewController *vc = [self.assembly customerListController]
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 can be of type TyphoonComponentFactory . . .
//. . . or any of your TyphoonAssembly sub-classes.
_factory = theFactory;
}
#Injecting Configuration
Besides injecting other Typhoon-built components, Typhoon can perform configuration by injecting simple objects and primitive values.
[definition injectProperty:@selector(serviceUrl) with:
[NSURL URLWithString:@"http://www.myapp.com/service"]];
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
If you wish, configuration information can also be extracted into a properties, plist or json file that can be stored locally or resolved dynamically.
<plist version="1.0">
<dict>
<key>damsels.rescued</key>
<integer>12</integer>
<key>hasHorseWillTravel</key>
<false/>
<key>service.url</key>
<string>NSURL(http://my.backend.net/service-gateway)</string>
</dict>
</plist>
#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)
{
"damsels.rescued": 12,
"hasHorseWillTravel": false,
"service.url": "NSURL(http://my.backend.net/service-gateway)"
}
- (id)configurer
{
return [TyphoonDefinition withConfigName:@"Configuration.properties"];
}
TyphoonConfigPostProcessor* configurer =
[TyphoonConfigPostProcessor forResourceNamed:@"Configuration.properties"];
[assembly attachPostProcessor:configurer];
. . And now reference a value as follows:
[definition injectProperty:@selector(serviceUrl) with:
TyphoonConfig(@"service.url")
- Global level (available from every assembly)
- Per-assembly level (available only from one assembly)
Global TyphoonConfigs
can be registered in four ways:
- By listing all of the global config filenames in the
Info.plist
under the keyTyphoonGlobalConfigFilenames
. - By implementing the method
-(NSArray *)globalConfigFilenames
in theAppDelegate
. - By adding the file with name
config_BUNDLEID.plist
, whereBUNDLEID
is the main bundle ID. - By attaching
TyphoonConfigPostProcessor
manually.
Scope of TyphoonConfigs
created via the definition in an assembly is limited to TyphoonDefinitions
from the same assembly.
Notice in the example above how service.url
is declared as NSURL(http://my.backend.net/service-gateway)
, and Typhoon injects as NSURL
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
- What can be Injected
- Auto-injection (Objective-C)
- Scopes
- Storyboards
- TyphoonLoadedView
- Activating Assemblies
Become a Typhoon expert.
For contributors or curious folks.