You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+78-13Lines changed: 78 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,8 @@
1
1
# ioc_container
2
2
A lightweight, flexible, and high-performance dependency injection and service location library for Dart and Flutter.
3
3
4
+
Version 2 of the library introduces the groundbreaking [async locking](#v2-and-async-locking) feature for singletons, a feature that's set to revolutionize the way you handle asynchronous initialization in Dart and Flutter! ioc_container is the only known container that offers this feature.
@@ -13,6 +15,8 @@ A lightweight, flexible, and high-performance dependency injection and service l
13
15
14
16
[Dependency Injection](#dependency-injection-di)
15
17
18
+
[Version 2 and Async Locking](#v2-and-async-locking)
19
+
16
20
[Why Use This Library?](#why-use-this-library)
17
21
18
22
[Performance And Simplicity](#performance-and-simplicity)
@@ -25,8 +29,6 @@ A lightweight, flexible, and high-performance dependency injection and service l
25
29
26
30
[Scoping and Disposal](#scoping-and-disposal)
27
31
28
-
[Async Initialization](#async-initialization)
29
-
30
32
[Testing](#testing)
31
33
32
34
[Add Firebase](#add-firebase)
@@ -40,6 +42,71 @@ Containers and service locators give you an easy way to lazily create the depend
40
42
## Dependency Injection (DI)
41
43
[Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) (DI) allows you to decouple concrete classes from the rest of your application. Your code can depend on abstractions instead of concrete classes. It allows you to easily swap out implementations without changing your code. This is great for testing, and it makes your code more flexible. You can use test doubles in your tests, so they run quickly and reliably.
42
44
45
+
## V2 and Async Locking
46
+
47
+
Imagine a scenario where you need to initialize a service, like Firebase, connect to a database, or perhaps fetch some initial configuration data. These operations are asynchronous, and in a complex app, there's always a risk of inadvertently initializing the service multiple times, leading to redundant operations, wasted resources, and potential bugs.
48
+
49
+
Enter async locking: With this feature, you can perform your async initialization with the confidence that it will only ever run once. No matter how many times you request the service, the initialization logic is executed just a single time. This is not just about efficiency; it's about ensuring the consistency and reliability of your services.
50
+
51
+
Version 2 brings this powerful new feature. This is perfect for initializing Firebase, connecting to a database, or any other async initialization work. You can initialize anywhere in your code and not worry that it might happen again. Furthermore, the singleton never gets added to the container until the initialization completes successfully. This means that you can retry as many times as necessary without the container holding on to a service in an invalid state.
52
+
53
+
Notice that this example calls the initialization method three times. However, it doesn't run the work three times. It only runs once. The first call to `getAsync()` starts the initialization work. The second and third calls to `getAsync()` wait for the initialization to complete.
You can do initialization work when instantiating an instance of your service. Use `addAsync()` or `addSingletonAsync()` to register the services. When you need an instance, call the `getAsync()` method instead of `get()`.
107
+
108
+
Check out the [retry package](https://pub.dev/packages/retry) to add resiliency to your app. Check out the [Flutter example](https://github.com/MelbourneDeveloper/ioc_container/blob/f92bb3bd03fb3e3139211d0a8ec2474a737d7463/example/lib/main.dart#L74) that displays a progress indicator until the initialization completes successfully.
109
+
43
110
## Why Use This Library?
44
111
This library makes it easy to
45
112
- Easily replace services with mocks for testing
@@ -51,7 +118,7 @@ This library makes it easy to
51
118
- It's standard. It aims at being a standard dependency injector so anyone who understands DI can use this library.
52
119
53
120
### Performance and Simplicity
54
-
This library is objectively fast and holds up to comparable libraries in terms of performance. See the [benchmarks](https://github.com/MelbourneDeveloper/ioc_container/tree/main/benchmarks)project and results.
121
+
This library is objectively fast and holds up to comparable libraries in terms of performance. These [benchmarks](https://github.com/MelbourneDeveloper/ioc_container/tree/main/benchmarks)are currently out of data for v2 beta but new benchmarks and performance options are coming.
55
122
56
123
The [source code](https://github.com/MelbourneDeveloper/ioc_container/blob/main/lib/ioc_container.dart) is a fraction of the size of similar libraries and has no dependencies. According to [codecov](https://app.codecov.io/gh/melbournedeveloper/ioc_container), it weighs in at 81 lines of code, which makes it the lightest container I know about. It is stable and has 100% test coverage. At least three apps in the stores use this library in production.
57
124
@@ -75,7 +142,7 @@ This will add a line like this to your package's `pubspec.yaml` (and run an impl
75
142
76
143
```yaml
77
144
dependencies:
78
-
ioc_container: ^1.0.9## Or, latest version
145
+
ioc_container: ^2.0.0-beta## Or, latest version
79
146
```
80
147
81
148
## Getting Started
@@ -116,8 +183,11 @@ void main() {
116
183
final builder = IocContainerBuilder()
117
184
//The app only has one AuthenticationService for the lifespan of the app (Singleton)
118
185
..addSingletonService(AuthenticationService())
119
-
//We mint a new UserService/ProductService for each usage
//We create a new UserService/ProductService for each usage
187
+
..add((container) => UserService(
188
+
//This is shorthand for container.get<AuthenticationService>()
189
+
container<AuthenticationService>()
190
+
))
121
191
..add((container) => ProductService());
122
192
123
193
// Build the container
@@ -296,13 +366,6 @@ The main function creates a scope to retrieve the `UserRepository` from the scop
296
366
297
367
*Note: all services in the scoped container exist for the lifespan of the scope. They act in a way that is similar to singletons, but when we call `dispose()` on the scope, it calls `dispose()` on each service registration.*
298
368
299
-
## Async Initialization
300
-
You can do initialization work when instantiating an instance of your service. Use `addAsync()` or `addSingletonAsync()` to register the services. When you need an instance, call the `getAsync()` method instead of `get()`.
301
-
302
-
_Warning: if you get a singleton with `getAsync()` and the call fails, the singleton will always return a `Future` with an error for the lifespan of the container._ You may need to take extra precautions by wrapping the initialization in a try/catch and using a retry. You may need to eventually cancel the operation if retrying fails. For this reason, you should probably scope the container and only use the result in your main container once it succeeds.
303
-
304
-
Check out the [retry package](https://pub.dev/packages/retry) to add resiliency to your app. Check out the [Flutter example](https://github.com/MelbourneDeveloper/ioc_container/blob/f92bb3bd03fb3e3139211d0a8ec2474a737d7463/example/lib/main.dart#L74) that displays a progress indicator until the initialization completes successfully.
0 commit comments