kiwi
A simple yet efficient IoC container for Dart and Flutter.
The container does not rely on reflection, it's just a Map
, so it's fast.
IMPORTANT: Dart2 is required to use this package.
This package can be used with, or without code generation. While code generation allows you to code faster, it comes with extra configuration on you side (to be setup only one time). This section is only about kiwi which contains the IoC container and the annotations. If you are looking for the kiwi_generator configuration, you can find documentation here.
Configuration
Add kiwi
to pubspec.yaml
under the dependencies
field.
The latest version is
dependencies:
kiwi: ^latest_version
Import
In your library add the following import:
import 'package:kiwi/kiwi.dart';
Usage
The core of kiwi is the KiwiContainer
class. This is where all your instances and factories are stored.
The KiwiContainer
is implemented as a singleton, you can access the single instance like this:
KiwiContainer container = KiwiContainer();
Note: I promise you, even if this is looking like a constructor, you will always end up with the same instance :wink:.
If you want different containers, you can create scoped ones easily:
KiwiContainer container = KiwiContainer.scoped();
It works like a lot of IoC containers: you can register a factory under a type, and then resolve the type to get a value.
Registering
You can register 3 kinds of objects:
Instances
Kiwi can register simple instances like that:
container.registerInstance(Sith('Anakin', 'Skywalker'));
You can also give a name to a specific instance:
container.registerInstance(Sith('Anakin', 'Skywalker'), name: 'DartVader');
By default instances are registered under their type. If you want to register an instance under a supertype: you have only need to add the super type in the generics. The subtype will be detected automatically:
container.registerInstance<Character>(Sith('Anakin', 'Skywalker'), name: 'DartVader');
In the above example Character
is a supertype of Sith
.
Factories
container.registerFactory((c) => Sith('Anakin', 'Skywalker'));
You can also give a name to a specific factory:
container.registerFactory((c) => Sith('Anakin', 'Skywalker'), name: 'DartVader');
By default factories are registered under the return type of the factory. If you want to register an factory under a supertype, you have to specify both of them:
container.registerFactory<Character>((c) => Sith('Anakin', 'Skywalker'), name: 'DartVader');
Note: the c
parameter is the instance of the KiwiContainer
, we will see later how it can be useful.
Singletons
Singletons are registered like factories but they are called only once: the first time we get their value.
container.registerSingleton((c) => Sith('Anakin', 'Skywalker'));
Resolving
You can get the instance registered for a type like this:
Sith theSith = container.resolve<Sith>();
If it was registered under a name, you can get its value like this:
Sith theSith = container.resolve<Sith>('DartVader');
If it was registered with a superclass, you can get its value like this:
Sith theSith = container.resolveAs<Character, Sith>();
If it was registered with a superclass under a name, you can get its value like this:
Sith theSith = container.resolveAs<Character, Sith>('DartVader');
The KiwiContainer
is a callable class. You can also resolve a type like that:
Sith theSith = container<Sith>('DartVader');
Usage with dependencies
If you have a service that depends on another, you have to add the dependency in the constructor. For registering the service, you can then use the c
parameter we saw earlier to resolve the value.
class Service {}
class ServiceA extends Service {}
class ServiceB extends Service {
ServiceB(ServiceA serviceA);
}
...
// Registers a complex factory by resolving the dependency
// when the type is resolved.
KiwiContainer container = KiwiContainer();
container.registerFactory((c) => ServiceB(c.resolve<ServiceA>()));
For services with a lot of dependencies, it can be tedious to write that sort of code. That's why kiwi comes with a generator :smiley:!
Unregistering
You can unregister a factory/instance at any time:
// Unregisters the Sith type.
container.unregister<Sith>();
// Unregister the Sith type that was registered under the name DartVader.
container.unregister<Sith>('DartVader');
Cleaning
You can remove all the registered types by calling the clear
method:
container.clear();
Ignoring KiwiErrors in development mode
By default kiwi throws an KiwiError
in the following cases:
- if you register the same type under the same name a second time.
- if you try to resolve a type that was not previously registered.
- if you try to unregister a type that was not previously registered.
This helps you to prevent potential errors in production, however you might want to ignore these KiwiErrors. To do this you can set true
to the silent
property of the KiwiContainer
:
container.silent = true;
In production, or when silent
is true
, you will get null
if you try to resolve a type that was not previously registered.
Changelog
Please see the Changelog page to know what's recently changed.