-
Notifications
You must be signed in to change notification settings - Fork 268
When to use runtime arguments
Back to Types of Injections
Typhoon allows defining components with run-time arguments, in order to implement the factory pattern.
The factory pattern is a common good practice to create objects that mix both dependencies and parametrization. Factories are also very suited to “hide” dependencies of the created objects, which the creator does not have to care about. Factories are usually a lot of boilerplate code, prone to tedious repetition and human error. By defining components that mix static dependencies and run-time arguments, Typhoon can create these factories for you.
Here's a concrete example of when to use the factory pattern: Imagine having two view controllers with the following interfaces:
@interface FriendListViewController
- (instancetype)initWithUsersService:(UsersService *)usersService; // dependency
@end
@interface UserDetailsViewController
- (instancetype)initWithPhotoService:(PhotoService *)photoService // dependency
user:(User *)user;
@end
The FriendListViewController will show a list of users and the UserDetailsViewController will show the details (including a nice photo) for the user passed as an argument.
From those two interfaces it is obvious that ParentViewController is missing a piece to create instances of ChildViewController: the dependency of PhotoService. One solution will be making the ParentViewController also depend on PhotoService, but that is an artificial dependency and presents a lot of problems, such as a "dependency explosion" - the early instantiation of all of PhotoService's dependencies, leading to excessive memory consumption, and so on.
The best solution is to let ParentViewController use a factory that returns an instance of the ChildViewController for the required user.
Run-time arguments allow defining a factory on the assembly interface. Here is an example:
- (id)userDetailsControllerForUser:(User *)user
{
return [TyphoonDefinition withClass:[UserDetailsViewController class]
configuration:^(TyphoonDefinition *definition) {
[definition useInitializer:@selector(initWithPhotoService:user)
parameters:^(TyphoonMethod *initializer) {
[initializer injectParameterWith:[self photoService];
[initializer injectParameterWith:user];
}];
}];
}
So having defined the UserDetailsViewControllerWith a runtime argument, we can now inject the assembly on the FriendListViewController as follows:
- (id)friendListController
{
return [TyphoonDefinition withClass:[FriendListViewController class]
configuration:^(TyphoonDefinition *definition) {
[definition injectProperty:@selector(assembly) with:self];
}];
}
We can obtain a UserDetailsViewController with both the static and runtime dependencies as follows:
User* aUser = friendListController.selectedUser;
UserDetailsViewController* detailsController = [friendListController.assembly
userDetailsControllerForUser:aUser];
User* aUser = self.selectedUser;
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.