Let's say I have two classes Foo and Bar. I can construct a Bar independently of Foo, but Foo needs a Bar. In Typhoon I define these two components and use them in my applicaiton however at runtime when constructing a Foo the barId that I pass in appears to be passed down to the other Bar component as a <TyphoonInjectionByRuntimeArgument: 0x15ea4670, type=Undifined> and not the NSString that I passed in.
I'm probably doing it wrong.
What should I do differently?
@implementation Assembly
-(Foo *)fooWithFooId:(NSString *)fooId andBarId:(NSString *)barId {
return [TyphoonDefinition withClass:[Foo class] configuration:^(TyphoonDefinition* definition) {
[definition useInitializer:@selector(initWithFooId:andBar:) parameters:^(TyphoonMethod *initializer) {
[initializer injectParameterWith:fooId];
[initializer injectParameterWith:[self barWithId:barId]];
}];
}];
}
-(Bar *)barWithBarId:(NSString *)barId {
return [TyphoonDefinition withClass:[Bar class] configuration:^(TyphoonDefinition* definition) {
[definition useInitializer:@selector(initWithBarId:) parameters:^(TyphoonMethod *initializer) {
[initializer injectParameterWith:barId];
}];
}];
}
@end
////////
@implementation Foo
-(instancetype) initWithFooId:(NSString *)fooId andBar:(Bar *)bar
{
self = [super init];
self.fooId = fooId;
self.bar = bar;
return self;
}
@end
@implementation Bar
-(instancetype) initWithBarId:(NSString *)barId
{
self = [super init];
self.barId = barId;
return self;
}
@end
Update:
After further review the issue appeared to be caused by using the runtime argument inside the definition to build another parameter for another definition. See the usage of NSString below:
@implementation Assembly
-(Foo *)fooWithFooId:(NSString *)fooId andBazId:(NSString *)bazId {
return [TyphoonDefinition withClass:[Foo class] configuration:^(TyphoonDefinition* definition) {
[definition useInitializer:@selector(initWithFooId:andBaz:) parameters:^(TyphoonMethod *initializer) {
[initializer injectParameterWith:fooId];
[initializer injectParameterWith:[self bazWithPathToBaz:[NSString stringWithFormat:@"/some/path/to/baz/%@", bazId]]];
}];
}];
}
-(Baz *)bazWithPathToBaz:(NSString *)bazPath {
return [TyphoonDefinition withClass:[Baz class] configuration:^(TyphoonDefinition* definition) {
[definition useInitializer:@selector(initWithBazPath:) parameters:^(TyphoonMethod *initializer) {
[initializer injectParameterWith:bazPath];
}];
}];
}
@end
When called the path passed into the initializer would come be "/some/path/to/baz/<TyphoonInjectionByRuntimeArgument: 0x15ea4670, type=Undifined>"
How are you obtaining your built instance of
Foo? Your assembly code above looks OK, but keep in mind the following:TyphoonDefinition. Typhoon instruments this assembly to collect the information that it needs to return built instances at runtime. This includes injecting runtime arguments with proxies (instances ofTyphoonInjectionByRuntimeArgument).TyphoonComponentFactory).After creating one ore more assemblies, the following is required to have the assembly return a built component:
Result:
<Foo: self.fooId=1234, self.bar=<Bar: self.barId=5678>>(or in the case of an app you could use plist-integration to bootstrap Typhoon and inject the app delegate. Note that you can inject the assembly itself into any component, either as a
TyphoonComponentFactoryor posing as one of your assembly interfaces. This is useful to transition from one object-graph (eg view controller) to another.)Edit:
Although it wasn't the original intention, in most cases you can also use run-time arguments from within an assembly, and we now do this in our own apps. For example:
. . but currently its not possible to create a top-level definition that is the result of another definition with runtime arguments. Example:
. . the reason is fairly simple, and if you need this we can look at it.